Wie mache ich Top 1 in Oracle?


251

Wie mache ich folgendes?

select top 1 Fname from MyTbl

In Oracle 11g ?




3
Können Sie uns die Reihenfolge mitteilen, nach der Sie "Top 1" möchten?
Andrew Wolfe

1
Zuallererst sollten Sie sich niemals auf die DB-Engine verlassen, um dies zu tun. Wenn Sie solche Dinge wissen möchten, setzen Sie einen Sequenzer ein. Wenn Sie dies tun, wird garantiert, dass sie in der Reihenfolge nummeriert werden, in der sie eingefügt wurden.
FlyingGuy

1
Sehr nützliches Material zu diesem Thema use-the-index-luke.com/sql/partial-results/top-n-queries
Ilia

Antworten:


257

Wenn Sie nur eine erste ausgewählte Zeile möchten, können Sie:

select fname from MyTbl where rownum = 1

Sie können auch Analysefunktionen verwenden, um das oberste x zu bestellen und zu übernehmen:

select max(fname) over (rank() order by some_factor) from MyTbl

54
Dies ist gut, wenn Sie nur 1 Zeile möchten und es egal ist, welche. Wenn Sie bestimmte Zeilen wie den letzten Datensatz möchten, müssen Sie die Sortierung in einer Unterauswahl durchführen, wie z. B. die Antwort von Vash. Oracle weist vor der Sortierung Rownums zu.
Scott Bailey

4
@ Scott yup. das ist richtig. Und Patrick, guter Punkt, ich denke, die Syntax ist in dieser Hinsicht falsch. Es sollte wirklich ein Keep Over sein (dens_rank () last ...)
mcpeterson

2
Der Unterschied zwischen dem ersten und dem zweiten Beispiel besteht darin, dass das erste eine Zeile auswählt (eine beliebige Zeile ohne Reihenfolge). Das zweite Beispiel erhält den Wert der ersten Zeile, ohne eine innere Abfrage der Reihenfolge durchzuführen (wie in den folgenden Beispielen gezeigt).
JulesLt

3
Die Syntax ist nicht korrekt in: Wählen Sie max (fname) über (rank () order by some_factor) von MyTbl
Stéphane Gerber

1
@jclozano "keine sehr bekannte Funktionalität von Orakel" - In Bezug auf Respekt bitte ich zu unterscheiden. Dies ist wichtig, da "nicht bekannte Funktionen" dazu neigen, Unklarheiten zu implizieren, und daher vorschlagen könnten, dass wir die Verwendung vermeiden sollten. Dies ist nicht unklar, und seine Verwendung sollte nicht vermieden werden.
September

166
SELECT *
  FROM (SELECT * FROM MyTbl ORDER BY Fname )
 WHERE ROWNUM = 1;

8
Diese Antwort erhält die TOP-Zeile korrekt (ordnet die Ergebnisse an, bevor ROWNUM eingeschränkt wird).
JulesLt

Diese Antwort ist keine exakte Übersetzung - die ursprüngliche Abfrage hat weder ein ORDER BY noch gibt sie alle Spalten in der Tabelle zurück.
OMG Ponys

Ich stehe korrigiert (siehe unten). Wechselt die Stimmen, sobald die Zeit abgelaufen ist.
JulesLt

7
@OMGPonies ja. Aber es ist wahrscheinlich das, was die meisten Leute wirklich wollen, die auf diese Seite kommen,
indem sie

4
Dies muss auf jeden Fall die beste Antwort in diesem Thread sein. Ich könnte eine Notiz hinzufügen, die top Xman ändern kann inWHERE ROWNUM <= X
SomethingSomething

31

Mit Oracle 12c (Juni 2013) können Sie es wie folgt verwenden.

SELECT * FROM   MYTABLE
--ORDER BY COLUMNNAME -OPTIONAL          
OFFSET 0 ROWS FETCH NEXT 1 ROWS ONLY

6
Interessanter Befehl, ich verwende hier 12c und das ist OFFSET 0 ROWSanscheinend nicht notwendig, Sie können verwenden FETCH NEXT 1 ROWS ONLYoder sogar FETCH FIRST ROW ONLY, die Reihenfolge nach ist wichtig oder es wird gleichbedeutend sein, nur a zu verwenden WHERE rownum = 1. Ich habe es sogar in einer OUTER APPLY-Anweisung versucht und es hat dort wie die TOP-Funktion von Ms-SQL funktioniert.
Rafael Merlin

Sie haben Recht @RafaelMerlin. Nach Ihrem Beitrag habe ich erkannt, dass OFFSET 0 ROWS nicht erforderlich ist. Es wäre nützlich, wenn Daten zwischen Top X und Top Y abgerufen werden.
MSK


So weit so gut, mit einem wichtigen fehlenden Punkt, der ist TIES. Siehe dies für die Fälle , in denen Bindungen auftreten für Version 12c +und12c -
Barbaros Özhan

10

Sie können ROW_NUMBER()eine ORDER BYKlausel in der Unterabfrage verwenden und diese Spalte anstelle von verwenden TOP N. Dies kann Schritt für Schritt erklärt werden.

Siehe die folgende Tabelle mit zwei Spalten NAMEund DT_CREATED.

Geben Sie hier die Bildbeschreibung ein

Wenn Sie unabhängig davon nur die ersten beiden Daten verwenden müssen NAME, können Sie die folgende Abfrage verwenden. Die Logik wurde in die Abfrage geschrieben

-- The number of records can be specified in WHERE clause
SELECT RNO,NAME,DT_CREATED
FROM
(
    -- Generates numbers in a column in sequence in the order of date
    SELECT ROW_NUMBER() OVER (ORDER BY DT_CREATED) AS RNO,
    NAME,DT_CREATED
    FROM DEMOTOP
)TAB
WHERE RNO<3;

ERGEBNIS

Geben Sie hier die Bildbeschreibung ein

In einigen Situationen müssen wir die TOP Njeweiligen Ergebnisse auswählen NAME. In diesem Fall können wir PARTITION BYmit einer ORDER BYKlausel in der Unterabfrage verwenden. Beziehen Sie sich auf die folgende Abfrage.

-- The number of records can be specified in WHERE clause
SELECT RNO,NAME,DT_CREATED
FROM
(
  --Generates numbers in a column in sequence in the order of date for each NAME
    SELECT ROW_NUMBER() OVER (PARTITION BY NAME ORDER BY DT_CREATED) AS RNO,
    NAME,DT_CREATED
    FROM DEMOTOP
)TAB
WHERE RNO<3;

ERGEBNIS

Geben Sie hier die Bildbeschreibung ein


1
Die Verwendung von ROW_NUMBER () ... ist eine korrektere Lösung als in der Themenantwort. Ein Problem mit dieser Lösung (und auch mit der max (Feld) -Variante), dass Sie Dinge wie "select ... (select ROW_NUMBER () ...) for update ;" nicht ausführen können ;
Alexo Po.

Und es ist manchmal sehr wichtig in PL / SQL (leider konnte der vorherige Kommentar nicht innerhalb von 5 Minuten bearbeitet werden).
Alexo Po.

In diesem Fall können wir CTE wie im äußeren Teil verwenden. Richtig? @ Alexo Po.
Sarath Avanavu

Ich glaube ich verstehe dich nicht. Die for update- Klausel kann verwendet werden, wenn ROWID von Oracle "leicht" beibehalten wird. Das Gruppieren (und das Gruppieren aufgrund der Verwendung von Analyseklauseln) verbirgt also echte ROWID und Zeilen können nicht gesperrt werden. Und zweitens with (select ... ) as ändert CTE ( Klausel) nichts an diesem Problem. CTE zielt nur darauf ab, Abfragen zu lesen und zu unterstützen. Richtig? @ Sarath Avanavu
Alexo Po.

Notiz an mich. Das Problem mit ROWID tritt tatsächlich speziell aufgrund der Bedingung RNO <3 auf. In diesem Fall ist der Wert von RNO nicht mit ROWID verbunden, sodass Oracle keine Zeilen sperren kann.
Alexo Po.

9

Sie können so etwas tun

    SELECT *
      FROM (SELECT Fname FROM MyTbl ORDER BY Fname )
 WHERE rownum = 1;

Sie können auch die Analysefunktionen RANK und / oder DENSE_RANK verwenden , aber ROWNUM ist wahrscheinlich die einfachste.


1
Kannst

9
select * from (
    select FName from MyTbl
)
where rownum <= 1;

5

Verwenden:

SELECT x.*
  FROM (SELECT fname 
          FROM MyTbl) x
 WHERE ROWNUM = 1

Wenn Sie Oracle9i + verwenden, können Sie Analysefunktionen wie ROW_NUMBER () verwenden, die jedoch nicht so gut wie ROWNUM funktionieren .


1
Schöne Antwort, enthält aber einen winzigen Tippfehler. Wo Sie Oracle9i + sagen, sollte das nicht 8i sein? download-west.oracle.com/docs/cd/A87860_01/doc/server.817/…
Ian Carpenter

@carpenteri: Richtig, Analytics waren in 8i verfügbar - ich kann mich nicht an die Details erinnern, aber Analytics waren der Öffentlichkeit erst in 9i wirklich verfügbar.
OMG Ponys

Kleiner Kommentar - Vashs Antwort unten enthält ein ORDER BY für die innere Abfrage, was wichtig ist, wenn Sie den TOP-Wert von fname anstelle von 'first' möchten (was alles sein kann, höchstwahrscheinlich die erste eingefügte Zeile). Könnte eine Bearbeitung wert sein?
JulesLt

@JulesLt: Die vom OP bereitgestellte Abfrage enthält kein ORDER BY. Dies ist also eine Antwort, die eine exakte Übersetzung in die Oracle-Syntax darstellt.
OMG Ponys

Mein Missverständnis der SQL SERVER TOP-Syntax (fälschlicherweise angenommen, dass sie FIRST in RANK und nicht ROWNUM ähnelt). Abgestimmt.
JulesLt

3

Das Auswählen der ersten Zeile aus einer Tabelle und das Auswählen einer Zeile aus einer Tabelle sind zwei verschiedene Aufgaben und erfordern eine andere Abfrage. Es gibt viele Möglichkeiten, dies zu tun. Vier davon sind:

Zuerst

select  max(Fname) from MyTbl;

Zweite

select  min(Fname) from MyTbl;

Dritte

select  Fname from MyTbl  where rownum = 1;

Vierte

select  max(Fname) from MyTbl where rowid=(select  max(rowid) from MyTbl)

3

Ich hatte das gleiche Problem und kann es mit dieser Lösung beheben:

select a.*, rownum 
from (select Fname from MyTbl order by Fname DESC) a
where
rownum = 1

Sie können Ihr Ergebnis vorher bestellen, um den ersten Wert oben zu haben.

Viel Glück

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.