2013-02-26 7 views
84

Ich habe Schwierigkeiten, gespeicherte Prozeduren von SQL Server in Oracle zu konvertieren, damit unser Produkt damit kompatibel ist.Wie Oracle ORDER BY und ROWNUM korrekt verwenden?

Ich habe Anfragen, die die jüngste Aufzeichnung einiger Tabellen zurückgibt, basierend auf einem Zeitstempel:

SQL Server:

SELECT TOP 1 * 
FROM RACEWAY_INPUT_LABO 
ORDER BY t_stamp DESC 

=> Das wird kehrt mir den jüngsten Rekord

Aber Oracle:

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

=> Das gibt mir den ältesten Datensatz (wahrscheinlich abhängig vom Index), unabhängig von der ORDER BY Aussage!

I verkapselt die Abfrage Oracle auf diese Weise meine Anforderungen entsprechen:

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

und es funktioniert. Aber es klingt wie ein schrecklicher Hack für mich, besonders wenn ich viele Platten in den beteiligten Tabellen habe.

Was ist der beste Weg, dies zu erreichen?

+0

[On ROWNUM und Limiting Ergebnisse] (http://www.oracle.com/technetwork/issue-archive/2006/06-sep/o56asktom-086197 hilft. html) –

+4

Was Sie in Ihrer letzten Abfrage getan haben, ist korrekt. Sie wählen die erste Zeile einer geordneten Liste von Datensätzen aus. Einfach Kapselung abfragen. – araknoid

+1

Dies wird im Handbuch eindeutig dokumentiert: http://docs.oracle.com/cd/E11882_01/server.112/e26088/pseudocolumns009.htm#i1006297 –

Antwort

84

Die where Anweisung wird ausgeführt vor die order by. Also, Ihre gewünschte Abfrage sagt "nehmen Sie die erste Zeile und dann bestellen Sie vont_stampdesc". Und das ist nicht das, was Sie vorhaben.

Die Unterabfrage-Methode ist die richtige Methode in Oracle.

Wenn Sie eine Version möchten, die in beiden Servern funktioniert, können Sie verwenden:

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

Die äußere * zurückkehren wird "1" in der letzten Spalte. Sie müssten die Spalten einzeln auflisten, um dies zu vermeiden.

19

Verwenden Sie stattdessen ROW_NUMBER(). ROWNUM ist eine Pseudosäule und ROW_NUMBER() ist eine Funktion. Sie können über den Unterschied zwischen ihnen lesen und den Unterschied in der Ausgabe von unten Abfragen sehen:

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' könnte schneller sein als' ROW_NUMBER() 'also, ob man einen verwenden sollte oder nicht über den anderen hängt von einer Reihe von Faktoren ab. –

0

Dokumentierte paar Design-Probleme mit diesem in einem Kommentar oben. Kurze Geschichte, in Oracle, müssen Sie die Ergebnisse manuell begrenzen, wenn Sie große Tabellen und/oder Tabellen mit gleichen Spaltennamen haben (und Sie nicht alle sie explizit eingeben und alle umbenennen möchten). Eine einfache Lösung besteht darin, Ihren Haltepunkt herauszufinden und diesen in Ihrer Abfrage zu begrenzen. Oder Sie können dies auch in der inneren Abfrage ausführen, wenn Sie nicht über die Einschränkung für widersprüchliche Spaltennamen verfügen. Zum Beispiel

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

wird die Ergebnisse erheblich reduzieren. Dann können Sie ORDER BY oder sogar die äußere Abfrage ausführen, um Zeilen zu begrenzen.

Auch denke ich, TOAD verfügt über eine Funktion, Zeilen zu begrenzen; aber, nicht sicher, dass das innerhalb der eigentlichen Abfrage auf Oracle einschränkt.Nicht sicher.

-2

Verwenden Sie einfach rownum wie folgt

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

Sieht dies wurde zweimal nach unten bewegt. Ich weiß, dass diese Lösung nicht gut funktioniert, aber ich weiß nicht warum. Würde jemand bitte erklären warum? Vielen Dank. – JasonGabler

+1

@JasonGabler 't' sollte' ril' sein. Sie haben diesen Tippfehler 3 Jahre später aus der angenommenen Antwort kopiert. Außerdem war dieser Code immer in der Frage. Es gibt keine Erklärung für "so", also erklärt es nichts. – philipxy

0

Ein alternatives ich in diesem Anwendungsfall vorschlagen würde, ist die MAX (t_stamp) zu verwenden, um die letzte Reihe zu bekommen ... z

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

Meine Codierungsmuster Präferenz (vielleicht) - zuverlässig, führt in der Regel zu oder besser als zu versuchen, die erste Zeile aus einer sortierten Liste wählen - auch die Absicht deutlicher lesbar ist.
Hope this ...

SQLer

+0

In Oracle gibt es kein LIMIT. Sie betteln die Frage an. – philipxy