Oracle ORDER BY ve ROWNUM nasıl doğru kullanılır?


126

Ürünümüzü onunla uyumlu hale getirmek için depolanan prosedürleri SQL Server'dan Oracle'a dönüştürmekte zorlanıyorum.

Zaman damgasına göre bazı tabloların en son kaydını döndüren sorgularım var:

SQL Server:

SELECT TOP 1 *
FROM RACEWAY_INPUT_LABO
ORDER BY t_stamp DESC

=> Bu bana en son kaydı döndürür

Ancak Oracle:

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

=> Bu, ORDER BYifadeden bağımsız olarak bana en eski kaydı döndürür (muhtemelen dizine bağlı olarak) !

Oracle sorgusunu gereksinimlerime uyacak şekilde özetledim:

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

ve çalışıyor. Ama bana korkunç bir hack gibi geliyor, özellikle de ilgili tablolarda çok fazla kaydım varsa.

Bunu başarmanın en iyi yolu nedir ?



4
Son Sorgunuzda yaptığınız şey doğrudur. Sıralı kayıt listesinin 1. satırını seçersiniz. Basitçe Sorgu kapsülleme.
araknoid

1
Bu, kılavuzda açıkça belgelenmiştir: docs.oracle.com/cd/E11882_01/server.112/e26088/…
a_horse_with_no_name

5
@a_horse_with_no_name Bu 404 hatasıyla açıkça belgelenmiş demek istiyorsun.
anthonybrice

3
@anthonybrice: teşekkürler. Oracle, tüm URL'lerini kılavuza değiştirdi. Güncel bağlantı: docs.oracle.com/cd/E11882_01/server.112/e41084/…
a_horse_with_no_name

Yanıtlar:


120

whereCümle çalışır önceorder by . Yani, istediğiniz sorgu " ilk satırı al ve sonra t_stamp desc ile sırala " diyor. Ve niyet ettiğin bu değil.

Alt sorgu yöntemi, Oracle'da bunu yapmak için uygun yöntemdir.

Her iki sunucuda da çalışan bir sürüm istiyorsanız, şunları kullanabilirsiniz:

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

Dış *, son sütunda "1" döndürür. Bundan kaçınmak için sütunları ayrı ayrı listelemeniz gerekir.


40

ROW_NUMBER()Bunun yerine kullanın . ROWNUMsözde sütundur ve ROW_NUMBER()bir işlevdir. Aralarındaki farkı okuyabilir ve aşağıdaki sorguların çıktısındaki farkı görebilirsiniz:

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
ROWNUMdaha hızlı olabilirdi, ROW_NUMBER()birinin diğerinin üzerinde kullanılıp kullanılmaması bir dizi faktöre bağlıdır.
David Faber

Olumsuz oy için özür dileriz, yanlışlıkla oldu! Maalesef şimdi geri alamam.
Athafoud

0

Bu kullanım durumunda önereceğim bir alternatif, en son satırı elde etmek için MAX (t_stamp) kullanmaktır ... ör.

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

Kodlama kalıbı tercihim (belki) - güvenilir, genellikle sıralı bir listeden 1. satırı seçmeye çalışırken veya daha iyi performans gösterir - ayrıca amaç daha açık bir şekilde okunabilir.
Bu yardımcı olur umarım ...

SQLer


3
Oracle'da SINIR yoktur. Soru için yalvarıyorsun.
philipxy

0

Yukarıdaki bir yorumda bununla ilgili birkaç tasarım sorunu belgelendi. Kısa hikaye, Oracle'da, aynı sütun adlarına sahip büyük tablolarınız ve / veya tablolarınız olduğunda sonuçları manuel olarak sınırlamanız gerekir (ve hepsini açık bir şekilde yazıp hepsini yeniden adlandırmak istemiyorsanız). Kolay çözüm, kesme noktanızı bulmak ve sorgunuzda bunu sınırlamaktır. Veya çakışan sütun adı kısıtlamasına sahip değilseniz, bunu iç sorguda da yapabilirsiniz. Örneğin

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

sonuçları önemli ölçüde azaltacaktır. Ardından SİPARİŞ VEREBİLİR veya satırları sınırlandırmak için dış sorguyu bile yapabilirsiniz.

Ayrıca TOAD'ın satırları sınırlama özelliği olduğunu düşünüyorum; ancak bunun Oracle'daki gerçek sorgu içinde sınırlandırdığından emin değilim. Emin değil.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.