653 Stimmen

Abrufen der Zeile, die den Max-Wert für eine Spalte enthält

Tabelle:

UserId, Value, Date.

Ich möchte die UserId, Wert für die max (Datum) für jede UserId zu erhalten. Das heißt, der Wert für jede UserId, die das späteste Datum hat. Gibt es eine Möglichkeit, dies einfach in SQL zu tun? (Vorzugsweise Oracle)

更新しました。 Entschuldigung für etwaige Unklarheiten: Ich muss ALLE UserIds abrufen. Aber für jede UserId, nur die Zeile, wo dieser Benutzer das neueste Datum hat.

4voto

Ich bin zwar ziemlich spät dran, aber der folgende Hack übertrifft sowohl korrelierte Unterabfragen als auch jede Analysefunktion, hat aber eine Einschränkung: Werte müssen in Zeichenketten konvertiert werden. Es funktioniert also für Daten, Zahlen und andere Zeichenketten. Der Code sieht nicht gut aus, aber das Ausführungsprofil ist großartig.

select
    userid,
    to_number(substr(max(to_char(date,'yyyymmdd') || to_char(value)), 9)) as value,
    max(date) as date
from 
    users
group by
    userid

Der Grund, warum dieser Code so gut funktioniert, ist, dass er die Tabelle nur einmal durchsuchen muss. Es sind keine Indizes erforderlich, und vor allem muss die Tabelle nicht sortiert werden, was bei den meisten Analysefunktionen der Fall ist. Indizes sind jedoch hilfreich, wenn Sie das Ergebnis nach einer einzelnen Benutzerkennung filtern müssen.

4voto

Truper Punkte 41

Ich musste einfach ein "Live"-Beispiel bei der Arbeit schreiben :)

Diese unterstützt mehrere Werte für UserId auf der dieselbe Datum.

Kolumnen: UserId, Wert, Datum

SELECT
   DISTINCT UserId,
   MAX(Date) OVER (PARTITION BY UserId ORDER BY Date DESC),
   MAX(Values) OVER (PARTITION BY UserId ORDER BY Date DESC)
FROM
(
   SELECT UserId, Date, SUM(Value) As Values
   FROM <<table_name>>
   GROUP BY UserId, Date
)

Sie können FIRST_VALUE anstelle von MAX verwenden und im Erklärungsplan nachschlagen. Ich hatte keine Zeit, damit zu spielen.

Natürlich ist es bei der Suche in großen Tabellen wahrscheinlich besser, wenn Sie FULL-Hinweise in Ihrer Abfrage verwenden.

4voto

markusk Punkte 5960

Utilice ROW_NUMBER() um eine eindeutige Rangfolge in absteigender Reihenfolge zu erstellen Date für jede UserId und filtern dann nach der ersten Zeile für jede UserId (d.h., ROW_NUMBER = 1).

SELECT UserId, Value, Date
FROM (SELECT UserId, Value, Date,
        ROW_NUMBER() OVER (PARTITION BY UserId ORDER BY Date DESC) rn
      FROM users) u
WHERE rn = 1;

3voto

Bruno Calza Punkte 2664

Wenn Sie Postgres verwenden, können Sie array_agg wie

SELECT userid,MAX(adate),(array_agg(value ORDER BY adate DESC))[1] as value
FROM YOURTABLE
GROUP BY userid

Ich bin mit Oracle nicht vertraut. Das habe ich mir ausgedacht

SELECT 
  userid,
  MAX(adate),
  SUBSTR(
    (LISTAGG(value, ',') WITHIN GROUP (ORDER BY adate DESC)),
    0,
    INSTR((LISTAGG(value, ',') WITHIN GROUP (ORDER BY adate DESC)), ',')-1
  ) as value 
FROM YOURTABLE
GROUP BY userid 

Beide Abfragen führen zu denselben Ergebnissen wie die akzeptierte Antwort. Siehe SQLFiddles:

  1. Akzeptierte Antwort
  2. Meine Lösung mit Postgres
  3. Meine Lösung mit Oracle

2voto

jdmichal Punkte 10727

Ich denke etwa so. (Verzeihen Sie mir etwaige Syntaxfehler; Ich bin es gewohnt, HQL an dieser Stelle zu verwenden!)

EDIT: Habe die Frage auch falsch gelesen! Habe die Abfrage korrigiert...

SELECT UserId, Value
FROM Users AS user
WHERE Date = (
    SELECT MAX(Date)
    FROM Users AS maxtest
    WHERE maxtest.UserId = user.UserId
)

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X