2013-02-26 13 views
84

Ho difficoltà a convertire le stored procedure da SQL Server a Oracle per avere il nostro prodotto compatibile con esso.Come utilizzare Oracle ORDER BY e ROWNUM correttamente?

devo query che restituisce il record più recente di alcune tabelle, sulla base di un timestamp:

SQL Server:

SELECT TOP 1 * 
FROM RACEWAY_INPUT_LABO 
ORDER BY t_stamp DESC 

=> Quella volontà mi restituisce il record più recente

Ma Oracle:

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

=> Ciò restituirà il record più vecchio (probabilmente in base all'indice), indipendentemente dall'istruzione ORDER BY!

ho incapsulati la query di Oracle in questo modo per abbinare le mie esigenze:

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

e funziona. Ma suona come un orribile scribacchino, specialmente se ho un sacco di dischi nelle tabelle coinvolte.

Qual è il modo migliore per raggiungere questo obiettivo?

+0

[On ROWNUM e Limitando Risultati] (http://www.oracle.com/technetwork/issue-archive/2006/06-sep/o56asktom-086197. html) –

+4

Quello che hai fatto nella tua ultima query è corretto. Si seleziona la prima riga di un elenco ordinato di record. Semplice incapsulamento delle query. – araknoid

+1

Questo è chiaramente documentato nel manuale: http://docs.oracle.com/cd/E11882_01/server.112/e26088/pseudocolumns009.htm#i1006297 –

risposta

84

L'istruzione where viene eseguita prima del il order by. Quindi, la domanda desiderata è "prendere la prima riga e quindi ordinarla pert_stampdesc". E non è quello che intendi.

Il metodo di subquery è il metodo corretto per farlo in Oracle.

Se volete una versione che funziona in entrambi i server, è possibile utilizzare:

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

L'esterno * torneranno "1" nell'ultima colonna. Dovresti elencare le colonne singolarmente per evitare questo.

19

Utilizzare invece ROW_NUMBER(). ROWNUM è una pseudocolonna e ROW_NUMBER() è una funzione. Si può leggere su differenza tra loro e vedere la differenza in uscita di query di seguito:

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' potrebbe essere più veloce di' ROW_NUMBER() 'quindi se si dovrebbe o non si dovrebbe usare uno sull'altro dipende da una serie di fattori. –

0

paio documentata di problemi di progettazione, con questo in un commento precedente. Breve storia, in Oracle, è necessario limitare manualmente i risultati quando si dispone di tabelle e/o tabelle di grandi dimensioni con gli stessi nomi di colonna (e non si desidera escluderli esplicitamente e rinominarli tutti). La soluzione facile è calcolare il punto di interruzione e limitarlo nella query. Oppure puoi anche farlo nella query interna se non hai il vincolo di nomi di colonne in conflitto. E.g.

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

ridurranno notevolmente i risultati. Quindi puoi ORDER BY o anche eseguire la query esterna per limitare le righe.

Inoltre, penso che TOAD abbia una funzione per limitare le righe; ma, non è sicuro che ciò limiti la query effettiva su Oracle.Non sono sicuro.

-2

Basta usare rownum come la seguente

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

Si vede che è stato downvoted due volte. So che questa soluzione non funziona bene, ma non so perché. Qualcuno potrebbe spiegare perché? Grazie. – JasonGabler

+1

@JasonGabler 't' dovrebbe essere' ril'. Hanno copiato questo errore dalla risposta accettata 3 anni dopo. Inoltre questo codice è sempre stato nella domanda. Non c'è spiegazione di "come questo", quindi non spiega nulla. – philipxy

0

Un supplente Vorrei suggerire in questo caso d'uso è quello di utilizzare il MAX (t_stamp) per ottenere l'ultima fila ... per esempio

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

La mia preferenza schema di codifica (forse) - affidabile, effettua generalmente pari o meglio che cercare di selezionare la 1 ° fila da un elenco ordinato - anche l'intento è più esplicitamente leggibile.
Spero che questo aiuti ...

SQLer

+0

Non c'è limite in Oracle. Stai elemosinando la domanda. – philipxy

Problemi correlati