2016-08-05 39 views
0

Ich habe eine Tabelle mit positions Diese Tabelle ist wie folgt:Einzelergebnis für user_id durch mehrere Daten sortiert

user_id | current | started_at | finished_at 
2  | false | 10-07-2016 | 02-08-2016 
1  | false | 19-07-2016 | 27-07-2016 
1  | true | 29-07-2016 | null 
3  | true | 20-07-2016 | null 
3  | false | 01-07-2016 | 18-07-2016 

ich diese Tabelle Sortier einen Fall entweder mit dem started_at oder finished_at Datum zu verwenden, je nach ob current wahr oder falsch ist

SELECT * 
FROM positions 
ORDER BY 
    CASE 
     WHEN current = true 
      THEN started_at 
     ELSE finished_at 
    END 
DESC 

Dies funktioniert wie erwartet, aber jetzt will ich nur die erste Zeile für jeden user_id

0 extrahieren

Also in meinem Beispiel Daten möchte ich nur folgendes zurückgegeben haben.

user_id | current | started_at | finished_at 
2  | false | 10-07-2016 | 02-08-2016 
1  | true | 29-07-2016 | null 
3  | true | 20-07-2016 | null 

ich nachdachte konnte mit einem GROUP BY getan werden, aber ich kann es nicht ohne Fehler zu arbeiten oder vielleicht brauche ich eine Sub-Abfrage, ich bin nicht sicher.

+0

Ist "nur die erste Zeile" gleich "WHERE current = true"? – Razzka

+0

Entschuldigung, das ist ein Fehler, korrigiert – Rob

Antwort

2

Dies ist eine hervorragende Möglichkeit, eine Fensterfunktion zu verwenden. Sie können die Fensterfunktion verwenden, um eine Abfrage zu erstellen, die wie folgt aussieht:

SELECT user_id, current, started_at, finished_at, 
    row_number() OVER (PARTITION BY user_id) AS row_number 
    FROM positions 
    ORDER BY CASE WHEN current = true 
     THEN started_at ELSE finished_at END DESC 

Dies werden Sie Ihre ursprüngliche Tabelle mit einer neuen Spalte „row_number“, die von der Fensterfunktion kommt. Sie partitionieren nach user_id, weil Sie die Zeilennummer nach Benutzer abrufen möchten. Verwenden Sie die ORDER-Klausel, die Sie angegeben haben. Um die vollständige Antwort zu erhalten, verwenden Sie einfach diese Anweisung als Unterabfrage, verwenden Sie die WHERE-Klausel, um nur Zeilennummer = 1 zu wählen, und ziehen Sie alle benötigten Felder. Fensterfunktionen können in der WHERE-Klausel nicht verwendet werden, weshalb Sie die Unterabfrage benötigen.

SELECT user_id, current, started_at, finished_at 
FROM 
(
SELECT user_id, current, started_at, finished_at, 
    row_number() OVER (PARTITION BY user_id) AS row_number 
FROM positions 
ORDER BY CASE WHEN current = true 
    THEN started_at ELSE finished_at END DESC 
) pos 
WHERE row_number= 1 
+0

Auch - wenn Sie Fensterfunktionen neu sind hier ist eine gute Dokumentation von PostgreSQL: [Fensterfunktionen] (https://www.postgresql.org/docs/9.1/static/tutorial-window.html) – MattPerry

+0

Danke für Ihre Hilfe Ich mag den Ansatz. Leider gibt es mir nicht die erwarteten Ergebnisse. Die Ergebnisse sind nicht nach Datumsspalten sortiert. Es bestellt von user_id http://pastebin.com/r5LkYXGC – Rob

+0

Ich sehe was du meinst. Ich habe die Antwort bearbeitet, um die Sortierung außerhalb der Partition durchzuführen, und habe die Funktion row_number() anstelle von rank() verwendet. Rank würde Ihnen doppelte "1" -Werte geben, wenn Sie genau die gleichen Daten für dieselbe user_id hätten.Ich weiß nicht, ob Ihr vollständiger Datensatz das hätte oder nicht - aber besser sicher. – MattPerry

0

Ich denke, Sie einen Fehler in Ihrem Beispiel gemacht, da das gewünschte Ergebnis zeigt die Sekunden Zeile für user_id 1.

Sie können ganz einfach erreichen, was Sie mit dem Nicht-Standard-PostgreSQL DISTINCT ON Feature wollen:

SELECT DISTINCT ON (user_id) * FROM 
    (SELECT * FROM positions 
    ORDER BY 
     CASE 
      WHEN current = true 
      THEN started_at 
      ELSE finished_at 
     END 
    DESC) q; 

Dadurch werden alle außer der ersten Zeile für jede user_id entfernt.

+0

Es ist die erste Zeile nach dem Datum sortiert das erwartete Ergebnis in meinem Beispiel ist richtig. Leider müssen Ihre Antwort Fehler "SELECT DISTINCT ON Ausdrücke müssen erste ORDER BY Ausdrücke übereinstimmen" – Rob

+0

In der Tat, tut mir leid. Ich habe die Antwort bearbeitet. –

+0

Danke für deine Hilfe @ laurenz-albe leider ist der resultierende Datensatz nicht nach dem in diesem Fall verwendeten Datum sortiert, da nur die innere Auswahl sortiert ist. Ich habe jetzt eine funktionierende Version von Matt. Danke für deinen Beitrag! – Rob