Subquery zurückzukehren, um den neuesten Eintrag für jeden Elternteil ID
Frage
Ich habe eine übergeordnete Tabelle mit Einträgen für Dokumente und ich habe eine Geschichte-Tabelle, die jedes Mal, wenn ein Benutzer greift auf eines der Dokumente einen Überwachungseintrag protokolliert.
Ich schreibe eine Suchabfrage eine Liste von Dokumenten (gefiltert nach verschiedenen Kriterien) mit der neuesten Benutzer-ID zurückzukehren jedem Dokument in der Ergebnismenge zuzugreifen.
So für
DOCUMENTS
ID | NAME
1 | Document 1
2 | Document 2
3 | Document 3
4 | Document 4
5 | Document 5
HISTORY
DOC_ID | USER_ID | TIMESTAMP
1 | 12345 | TODAY
1 | 11111 | IN THE PAST
1 | 11111 | IN THE PAST
1 | 12345 | IN THE PAST
2 | 11111 | TODAY
2 | 12345 | IN THE PAST
3 | 12345 | IN THE PAST
Ich würde schauen, um eine Rückkehr von meiner Suche wie
bekommen
ID | NAME | LAST_USER_ID
1 | Document 1 | 12345
2 | Document 2 | 11111
3 | Document 3 | 12345
4 | Document 4 |
5 | Document 5 |
Kann ich einfach dies mit einer SQL-Abfrage und eine Verknüpfung zwischen den beiden Tabellen?
Lösung
revidieren, was Andy White produziert und ersetzt eckige Klammern (MS SQL Server-Notation) mit DB2 (und ISO-Standard SQL) "begrenzter Bezeichner":
SELECT d.id, d.name, h.last_user_id
FROM Documents d LEFT JOIN
(SELECT r.doc_id AS id, user_id AS last_user_id
FROM History r JOIN
(SELECT doc_id, MAX("timestamp") AS "timestamp"
FROM History
GROUP BY doc_id
) AS l
ON r."timestamp" = l."timestamp"
AND r.doc_id = l.doc_id
) AS h
ON d.id = h.id
Ich bin mir nicht ganz sicher, ob „Zeitstempel“ oder „Timestamp“ richtig ist -. Wahrscheinlich letzteres
Der Vorteil hierbei ist, dass es die innere korrelierte Unterabfrage in Andys Version mit einer einfacheren nicht-korrelierten Unterabfrage ersetzt, die das Potenzial zu sein hat (radikal?) Effizienter zu gestalten.
Andere Tipps
ich nicht den „MIT MAX (timestamp)“ erhalten könnte in SQL Server laufen - ich erfordert wie „mit max (Zeitstempel)> 2009-03-05“ einen Booleschen Ausdruck erraten habe oder etwas, das nicht in diesem Fall keine Anwendung. (Ich könnte etwas falsch sein ...)
Hier ist etwas, das scheint zu funktionieren - man beachte die Verbindung hat zwei Bedingungen (nicht sicher, ob dies gut ist oder nicht):
select
d.ID,
d.NAME,
h."USER_ID" as "LAST_USER_ID"
from Documents d
left join History h
on d.ID = h.DOC_ID
and h."TIMESTAMP" =
(
select max("TIMESTAMP")
from "HISTORY"
where "DOC_ID" = d.ID
)
Dieses verwendet keine Join, aber für einige Anfragen wie diese Ich mag die Select für den Bereich Inline. Wenn Sie die Situation fangen wollen, wenn kein Benutzer zugegriffen hat, kann man es wickelt mit einem NVL ().
select a.ID, a.NAME,
(select x.user_id
from HISTORY x
where x.doc_id = a.id
and x.timestamp = (select max(x1.timestamp)
from HISTORY x1
where x1.doc_id = x.doc_id)) as LAST_USER_ID
from DOCUMENTS a
where <your criteria here>
Ich denke, es sollte wie folgt sein:
SELECT ID, Name, b.USER_ID as LAST_USER_ID
FROM DOCUMENTS a LEFT JOIN
( SELECT DOC_ID, USER_ID
FROM HISTORY
GROUP BY DOC_ID, USER_ID
HAVING MAX( TIMESTAMP )) as b
ON a.ID = b.DOC_ID
Dies könnte funktionieren auch:
SELECT ID, Name, b.USER_ID as LAST_USER_ID
FROM DOCUMENTS a
LEFT JOIN HISTORY b ON a.ID = b.DOC_ID
GROUP BY DOC_ID, USER_ID
HAVING MAX( TIMESTAMP )
Select ID, Name, User_ID
From Documents Left Outer Join
History a on ID = DOC_ID
Where ( TimeStamp = ( Select Max(TimeStamp)
From History b
Where a.DOC_ID = b.DOC_ID ) OR
TimeStamp Is NULL ) /* this accomodates the Left */