Ich habe zwei Tabellen namens record
und record_history
. Für jeden Datensatz kann es mehr als einen Verlauf geben. Sie können durch id
und verbunden werden record_id
. Ich möchte alle record
Einträge mit den neuesten record_history
Daten erhalten. Ich habe die Abfrage wie folgt erstellt:
SELECT rec.id, rec.name, rech1.data AS last_history_data
FROM record rec
LEFT OUTER JOIN record_history rech1 ON (rec.id = rech1.record_id)
LEFT OUTER JOIN record_history rech2 ON (rec.id = rech2.record_id AND rech2.ts > rech1.ts)
WHERE rech2.id IS NULL
ORDER BY rec.id DESC
Hier bekomme ich die neueste von ts
. Dies funktioniert, solange keine doppelten ts
Einträge vorhanden sind. Wenn der letzte Zeitstempel in wiederholt wird record_history
, gibt diese Abfrage mehr als eine Zeile für einen Datensatz zurück. Wie können wir das Limit hier auf der linken Verknüpfung anwenden, um doppelte Zeilen einzuschränken?
rech2
wird hier verwendet, wählen Sie die erste record_history und mein Bedürfnis nach rech2 soll seinNULL
Antworten:
Sofern Sie sich nicht in einer sehr alten Version von Postgres befinden, benötigen Sie keinen Double Join. Sie können das gleiche Ergebnis erzielen, indem Sie einen
LATERAL
Join verwenden .Die doppelten Ergebnisse können in Ihrer Methode vermieden werden, indem neben dem eine zweite Bedingung hinzugefügt wird
rec.id = rech2.record_id
. Mit derLATERAL
Join-MethodeLIMIT
wird dies ohnehin vermieden. Es kann nur 1 Zeile von der seitlichen Unterabfrage zurückgegeben werden. Wir können eine zweite Bedingung hinzufügen, damit die Auswahl deterministisch ist (aus zwei oder mehr Zeilen mit demselben Zeitstempel):In Bezug auf die Vorgehensweise mit der ursprünglichen Methode (2 Verknüpfungen und
IS NULL
Prüfung) können Sie dieON
Bedingung ändern - vorausgesetzt, dieid
Verlaufstabelle enthält eine Spalte, die eindeutig ist(id)
oder zumindest(ts, id)
eindeutig:Übrigens könnten Sie diesen zweiten
LEFT
Join ersetzen undIS NULL
mit einerNOT EXISTS
Unterabfrage mit denselben Ergebnissen und möglicherweise ähnlicher Effizienz prüfen (oder sogar mit einerNOT IN
Unterabfrage, obwohl dies besondere Sorgfalt für nullfähige Spalten erfordert, was nicht empfohlen wird).quelle
LATERAL
. Es ist ein gutes Lernen für mich. Vielen Dank!The duplicate results can be avoided in your method by adding a second condition besides the rec.id = rech2.record_id
Welche Bedingung können wir hier hinzufügen, um Doppelarbeit zu vermeiden?left join lateral .. on (true)
eher ein alsCROSS JOIN LATERAL ()
?record
ohne zugehörige Zeile vorhanden sindrecord_history
.record
Einträge, auch wenn es für einige keine Verlaufseinträge gibt.