2013-02-26 1 views
84

Мне сложно преобразовать хранимые процедуры из SQL Server в Oracle, чтобы наш продукт совместим с ним.Как правильно использовать Oracle ORDER BY и ROWNUM?

У меня есть вопросы, которые возвращает самую последнюю запись некоторых таблиц, на основе временной метки:

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 

и это работает. Но это звучит как ужасный хак для меня, особенно если у меня много записей в задействованных таблицах.

Каков наилучший способ достичь этого?

+0

[На ROWNUM и ограничение результатов] (http://www.oracle.com/technetwork/issue-archive/2006/06-sep/o56asktom-086197. html) –

+4

Что вы сделали в своем последнем запросе правильно. Вы выбираете первую строку упорядоченного списка записей. Просто инкапсуляция запроса. – araknoid

+1

Это явно задокументировано в руководстве: http://docs.oracle.com/cd/E11882_01/server.112/e26088/pseudocolumns009.htm#i1006297 –

ответ

84

Заявление where исполняется доorder by. Итак, ваш желаемый запрос говорит: «возьмите первый ряд, а затем закажите егоt_stampdesc». И это не то, что вы намереваетесь.

Метод подзапроса является правильным методом для этого в 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» в последнем столбце. Чтобы избежать этого, вам нужно будет отдельно указывать столбцы.

19

Вместо этого использовать 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 
+2

'ROWNUM' может быть быстрее, чем' ROW_NUMBER() ', так, нужно ли использовать один с другой зависит от ряда факторов. –

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') 

существенно сократит результаты. Затем вы можете ЗАКАЗАТЬ BY или даже сделать внешний запрос для ограничения строк.

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

-2

Просто используйте ROWNUM как следующий

select * 
from (select t.* 
     from raceway_input_labo ril 
     order by t_stamp desc 
    )  
where rownum = 1 
+0

Видно, что это было дважды опущено. Я знаю, что это решение работает не очень хорошо, но я не знаю почему. Кто-нибудь, пожалуйста, объясните, почему? Спасибо. – JasonGabler

+1

@JasonGabler 't' должен быть' ril'. Они копировали эту опечатку из принятого ответа через 3 года. Более того, этот код всегда был в вопросе. Нет никакого объяснения «подобного», поэтому он ничего не объясняет. – philipxy

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

+0

В Oracle нет LIMIT. Вы умоляете вопрос. – philipxy