Oracle SELECT TOP 10-Datensätze


144

Ich habe ein großes Problem mit einer SQL-Anweisung in Oracle. Ich möchte die von STORAGE_DB bestellten TOP 10-Datensätze auswählen, die nicht in einer Liste aus einer anderen select-Anweisung enthalten sind.

Dieser funktioniert gut für alle Datensätze:

SELECT DISTINCT 
  APP_ID, 
  NAME, 
  STORAGE_GB, 
  HISTORY_CREATED, 
  TO_CHAR(HISTORY_DATE, 'DD.MM.YYYY') AS HISTORY_DATE  
  FROM HISTORY WHERE 
      STORAGE_GB IS NOT NULL AND 
        APP_ID NOT IN (SELECT APP_ID
                       FROM HISTORY
                        WHERE TO_CHAR(HISTORY_DATE, 'DD.MM.YYYY') = '06.02.2009') 

Aber wenn ich hinzufüge

AND ROWNUM <= 10
ORDER BY STORAGE_GB DESC

Ich bekomme eine Art "zufällige" Platten. Ich denke, weil das Limit vor der Bestellung stattfindet.

Hat jemand eine gute Lösung? Das andere Problem: Diese Abfrage ist wirklich langsam (10k + Datensätze)


Wahrscheinliches Duplikat: stackoverflow.com/questions/2306744/…
APC

Antworten:


199

Sie müssen Ihre aktuelle Abfrage wie folgt in die Unterabfrage einfügen:

SELECT * FROM (
  SELECT DISTINCT 
  APP_ID, 
  NAME, 
  STORAGE_GB, 
  HISTORY_CREATED, 
  TO_CHAR(HISTORY_DATE, 'DD.MM.YYYY') AS HISTORY_DATE  
  FROM HISTORY WHERE 
    STORAGE_GB IS NOT NULL AND 
      APP_ID NOT IN (SELECT APP_ID FROM HISTORY WHERE TO_CHAR(HISTORY_DATE, 'DD.MM.YYYY') ='06.02.2009')
  ORDER BY STORAGE_GB DESC )
WHERE ROWNUM <= 10

Oracle wendet Rownum auf das Ergebnis an, nachdem es zurückgegeben wurde.
Sie müssen das Ergebnis filtern, nachdem es zurückgegeben wurde, daher ist eine Unterabfrage erforderlich. Sie können auch die Funktion RANK () verwenden, um Top-N-Ergebnisse zu erhalten.

Verwenden Sie für die Leistung NOT EXISTSanstelle von NOT IN. Sehen Sie dies für mehr.


NOT EXISTS funktioniert in diesem Szenario nicht (ungültiger Vergleichsoperator) APP_ID NOT EXISTS (SELEC ...)
opHASnoNAME

3
Einige mögen sagen, dass dies dazu neigt, Leute von Oracle auszuschalten.
MrBoJangles

2
Überprüfen Sie die FETCH NEXT N ROWS ONLYAntwort unten.
Mohnish

@Padmarag: Wann wird ein Rownum in einer Abfrage wie dieser angewendet? Wählen Sie * aus SomeTable aus, wobei someColumn = '123' und Rownum <= 3. Ist es nach Auswahl der Ergebnisse aus [Select * from SomeTable where someColumn = '123']
Shirgill Farhan

55

Wenn Sie Oracle 12c verwenden, verwenden Sie:

NUR NÄCHSTE N REIHEN ABRUFEN

SELECT DISTINCT 
  APP_ID, 
  NAME, 
  STORAGE_GB, 
  HISTORY_CREATED, 
  TO_CHAR(HISTORY_DATE, 'DD.MM.YYYY') AS HISTORY_DATE  
  FROM HISTORY WHERE 
    STORAGE_GB IS NOT NULL AND 
      APP_ID NOT IN (SELECT APP_ID FROM HISTORY WHERE TO_CHAR(HISTORY_DATE, 'DD.MM.YYYY') ='06.02.2009')
  ORDER BY STORAGE_GB DESC
FETCH NEXT 10 ROWS ONLY

Weitere Informationen: http://docs.oracle.com/javadb/10.5.3.0/ref/rrefsqljoffsetfetch.html


2
Dies ist Gold im Vergleich zu anderen Antworten
aswzen

Ich bin mit aswzen einverstanden
Austin Springer

1
Ich möchte dieser Antwort 100 positive Stimmen geben! Aber leider habe ich nur einen zu vergeben. Eins ist es!
Eidylon

23

In Bezug auf die schlechte Leistung gibt es eine Reihe von Dingen, die es sein könnte, und es sollte wirklich eine separate Frage sein. Es gibt jedoch eine offensichtliche Sache, die ein Problem sein könnte:

WHERE TO_CHAR(HISTORY_DATE, 'DD.MM.YYYY') = '06.02.2009') 

Wenn HISTORY_DATE wirklich eine Datumsspalte ist und einen Index hat, funktioniert dieses Umschreiben besser:

WHERE HISTORY_DATE = TO_DATE ('06.02.2009', 'DD.MM.YYYY')  

Dies liegt daran, dass eine Datentypkonvertierung die Verwendung eines B-Tree-Index deaktiviert.


22

Versuchen

SELECT * FROM users FETCH NEXT 10 ROWS ONLY;

11

Sie erhalten eine scheinbar zufällige Menge, da ROWNUM vor ORDER BY angewendet wird. Ihre Abfrage nimmt also die ersten zehn Zeilen und sortiert sie. 0 Um die zehn besten Gehälter auszuwählen, sollten Sie eine Analysefunktion in einer Unterabfrage verwenden und dann Folgendes filtern:

 select * from 
     (select empno,
             ename,
             sal,
             row_number() over(order by sal desc nulls last) rnm
    from emp) 
 where rnm<=10
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.