Як правильно користуватися Oracle ORDER BY і ROWNUM?


126

Мені важко перетворити збережені процедури з SQL Server в Oracle, щоб наш продукт був сумісний з ним.

У мене є запити, які повертають найновіший запис деяких таблиць на основі часової позначки:

SQL Server:

SELECT TOP 1 *
FROM RACEWAY_INPUT_LABO
ORDER BY t_stamp DESC

=> Це поверне мені останній запис

Але Oracle:

SELECT *
FROM raceway_input_labo 
WHERE  rownum <= 1
ORDER BY t_stamp DESC

=> Це поверне мені найстаріший запис (можливо, залежно від індексу), незалежно від ORDER BYтвердження!

Я записував запит Oracle таким чином, щоб відповідати моїм вимогам:

SELECT * 
FROM 
    (SELECT *
     FROM raceway_input_labo 
     ORDER BY t_stamp DESC)
WHERE  rownum <= 1

і це працює. Але це звучить як жахливий злом для мене, особливо якщо у мене багато записів у задіяних таблицях.

Який найкращий спосіб досягти цього?



4
Те, що ви зробили в своєму останньому запиті, є правильним. Ви вибираєте перший рядок упорядкованого списку записів. Просто інкапсуляція запитів.
аракноїд

1
Це чітко зафіксовано в посібнику: docs.oracle.com/cd/E11882_01/server.112/e26088/…
a_horse_with_no_name

5
@a_horse_with_no_name Ви маєте на увазі чітко задокументовану помилку 404.
anthonybrice

3
@anthonybrice: спасибі Oracle змінив усі свої URL-адреси в керівництві. Актуальне посилання: docs.oracle.com/cd/E11882_01/server.112/e41084/…
a_horse_with_no_name

Відповіді:


120

whereЗаява запускається на виконання , перш ніжorder by . Отже, у вашому бажаному запиті йдеться: " візьміть перший рядок, а потім впорядкуйте його за t_stamp desc ". І це не те, що ви маєте намір.

Метод підзапиту - це правильний спосіб зробити це в Oracle.

Якщо ви хочете, щоб версія, яка працює на обох серверах, ви можете використовувати:

select ril.*
from (select ril.*, row_number() over (order by t_stamp desc) as seqnum
      from raceway_input_labo ril
     ) ril
where seqnum = 1

Зовнішній *поверне "1" в останньому стовпчику. Вам потрібно буде перераховувати стовпці окремо, щоб цього уникнути.


40

Використовуйте ROW_NUMBER()замість цього. ROWNUMє псевдоколонкою і ROW_NUMBER()є функцією. Ви можете прочитати про різницю між ними та побачити різницю у виведенні нижче запитів:

SELECT * FROM (SELECT rownum, deptno, ename
           FROM scott.emp
        ORDER BY deptno
       )
 WHERE rownum <= 3
 /

ROWNUM    DEPTNO    ENAME
---------------------------
 7        10    CLARK
 14       10    MILLER
 9        10    KING


 SELECT * FROM 
 (
  SELECT deptno, ename
       , ROW_NUMBER() OVER (ORDER BY deptno) rno
  FROM scott.emp
 ORDER BY deptno
 )
WHERE rno <= 3
/

DEPTNO    ENAME    RNO
-------------------------
10    CLARK        1
10    MILLER       2
10    KING         3

3
ROWNUMможе бути швидше, ніж ROW_NUMBER()так, чи слід використовувати один чи інший залежно від ряду факторів.
Девід Фабер

Вибачте за низову промову помилково! На жаль, зараз я не можу це повернути.
Афафуд

0

Замінник, який я б запропонував у цьому випадку використання, - це використовувати MAX (t_stamp) для отримання останнього рядка ... наприклад

select t.* from raceway_input_labo t
where t.t_stamp = (select max(t_stamp) from raceway_input_labo) 
limit 1

Моє уподобання шаблону кодування (можливо) - надійне, як правило, виконує або краще, ніж намагається вибрати 1-й рядок із відсортованого списку - також намір є більш зрозумілим для читання.
Сподіваюся, це допомагає ...

SQLer


3
В Oracle немає обмежень. Ви благаєте питання.
philipxy

0

Документована пара проблем дизайну з цим у коментарі вище Коротка історія, в Oracle вам потрібно обмежити результати вручну, коли у вас є великі таблиці та / або таблиці з однаковими назвами стовпців (і ви не хочете, щоб явно вводити їх усі і перейменовувати їх усі). Просте рішення - з’ясувати точку перерви та обмежити це у вашому запиті. Або ви також можете зробити це у внутрішньому запиті, якщо у вас немає обмежень, що суперечать один одному. Напр

WHERE m_api_log.created_date BETWEEN TO_DATE('10/23/2015 05:00', 'MM/DD/YYYY HH24:MI') 
                                 AND TO_DATE('10/30/2015 23:59', 'MM/DD/YYYY HH24:MI')  

суттєво знизить результати Тоді ви можете ЗАМОВИТИ або навіть виконати зовнішній запит для обмеження рядків.

Крім того, я думаю, TOAD має особливість обмеження рядків; але, не впевнений, що це обмежує фактичний запит у Oracle. Не впевнений.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.