выбрать строки между двумя значениями в Oracle 11g - PullRequest
0 голосов
/ 26 августа 2018

Это распространенный вопрос, который я видел во многих местах, но пока не знаю, возможно это или нет. Я пытаюсь выбрать строки между 2 и 5 следующим образом, используя oracle sql developer tool.

В результате этого запроса следует выбрать 3-й и 4-й запрос в соответствии с запросом ниже

SELECT * FROM MyTable
WHERE ROWNUM > 2 AND ROWNUM < 5

но 3-я и 4-я строки не выбираются,

Тогда я попробовал следующий запрос

SELECT * FROM MyTable
WHERE RN BETWEEN 2 AND 5

Это также синтаксически и программно правильно, но без выбора точных столбцов.

Ответы [ 2 ]

0 голосов
/ 26 августа 2018

Немного аналитики.

Зарплаты в таблице EMP, отсортированные по $$$, выглядят так:

SQL> select ename, sal
  2  from emp
  3  order by sal;

ENAME             SAL
---------- ----------
SMITH             800
JAMES             950   2   you want to return James ...
WARD             1250   3
MARTIN           1250   4
MILLER           1300   5   ... to Miller
TURNER           1500
ALLEN            1600
CLARK            2450
BLAKE            2850
JONES            2975
FORD             3000
KING             5000

12 rows selected.

SQL>

Если вы сделаете это следующим образом, вы получите то, что хотели:

SQL> select ename, sal, rn
  2  from (select ename, sal, row_number() over (order by sal) rn
  3        from emp
  4       )
  5  where rn between 2 and 5;

ENAME             SAL         RN
---------- ---------- ----------
JAMES             950          2
WARD             1250          3
MARTIN           1250          4
MILLER           1300          5

SQL>

Однако, как видите, Уорд и Мартин зарабатывают одинаковые 1250 долларов. Итак, должны ли мы считать, что они имеют одинаковую зарплату и включить Тернера в список, или нет? Еще две аналитические функции могут помочь вам решить: RANK и DENSE_RANK:

SQL> select ename, sal,
  2    row_number() over (order by sal) rn,
  3    rank() over (order by sal) rnk,
  4    dense_rank() over (order by sal) drnk
  5  from emp
  6  order by sal;

ENAME             SAL         RN        RNK       DRNK
---------- ---------- ---------- ---------- ----------
SMITH             800          1          1          1
JAMES             950          2          2          2   2nd isn't questionable, but ...
WARD             1250          3          3          3
MARTIN           1250          4          3          3
MILLER           1300          5          5          4   ... which one is 5th? Miller (RN and RNK), ...
TURNER           1500          6          6          5   ... or Turner (DRNK column)?
ALLEN            1600          7          7          6
CLARK            2450          8          8          7
BLAKE            2850          9          9          8
JONES            2975         10         10          9
FORD             3000         11         11         10
KING             5000         12         12         11

12 rows selected.

SQL>

Если честно, DENSE_RANK, вероятно, лучший вариант в таких случаях:

SQL> select ename, sal, drnk
  2  from (select ename, sal, dense_rank() over (order by sal) drnk
  3        from emp
  4       )
  5  where drnk between 2 and 5;

ENAME             SAL       DRNK
---------- ---------- ----------
JAMES             950          2
WARD             1250          3
MARTIN           1250          3
MILLER           1300          4
TURNER           1500          5

SQL>

Теперь у вас есть несколько вариантов; выберите тот, который подходит вам лучше всего.

0 голосов
/ 26 августа 2018

Использовать подзапрос:

SELECT t.*
FROM (SELECT t.*, ROWNUM as rn
      FROM MyTable t
     ) t
WHERE rn > 2 AND rn < 5;

Обратите внимание, что таблицы представляют неупорядоченные наборы. Нет такого понятия, как первый или второй ряд. У вас должно быть предложение ORDER BY для указания порядка.

Причина, по которой ваша версия не работает, заключается в том, что rownum начинается с 1, когда первая строка помещается в набор результатов. Если строка не вставлена, значение никогда не увеличивается. Таким образом, он никогда не достигнет 2 или 3.

Следует также отметить, что between в SQL включительно. Так что >= и <= более уместны.

EDIT:

Следует отметить, что Oracle 12+ поддерживает FETCH / OFFSET:

select t.*
from mytable t
offset 2                  -- start on the third row
fetch first 2 rows only   -- fetch two rows in total

В этом случае по-прежнему рекомендуется order by.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...