Sous-requête pour retourner la dernière entrée pour chaque ID parent

StackOverflow https://stackoverflow.com/questions/625055

  •  05-07-2019
  •  | 
  •  

Question

J'ai une table parent avec des entrées pour les documents et une table d'historique qui enregistre une entrée d'audit chaque fois qu'un utilisateur accède à l'un des documents.

J'écris une requête de recherche pour renvoyer une liste de documents (filtrée selon divers critères) avec le dernier ID utilisateur permettant d'accéder à chaque document renvoyé dans l'ensemble de résultats.

Ainsi pour


    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

Je chercherais à obtenir un résultat de ma recherche comme


    ID | NAME       | LAST_USER_ID
    1  | Document 1 | 12345
    2  | Document 2 | 11111
    3  | Document 3 | 12345
    4  | Document 4 | 
    5  | Document 5 | 

Puis-je le faire facilement avec une requête SQL et une jointure entre les deux tables?

Était-ce utile?

La solution

Révision des produits d’Andy White et remplacement des crochets (notation MS SQL Server) par DB2 (et ISO standard SQL) "identificateurs délimités":

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

Je ne suis pas absolument certain que " timestamp " ou "TIMESTAMP" est correct - probablement le dernier.

L’avantage de cela est qu’elle remplace la sous-requête corrélée interne dans la version d’Andy par une sous-requête plus simple, non corrélée, qui a le potentiel d’être (radicalement?) plus efficace.

Autres conseils

Je n'ai pas pu obtenir le message "AYANT MAX (TIMESTAMP)". s'exécuter dans SQL Server - Je suppose qu'avoir besoin d'une expression booléenne telle que "having max" (TIMESTAMP) > 2009-03-05 " ou quelque chose qui ne s'applique pas dans ce cas. (Je pourrais faire quelque chose de mal ...)

Voici quelque chose qui semble fonctionner - notez que la jointure a 2 conditions (vous ne savez pas si c'est bon ou pas):

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
    )

Cela n’utilise pas de jointure, mais pour certaines requêtes de ce type, j’aime insérer la sélection dans le champ. Si vous souhaitez intercepter la situation quand aucun utilisateur n'a accédé, vous pouvez l'envelopper avec un 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>

Je pense que cela devrait ressembler à ceci:

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

cela pourrait également fonctionner:

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 */
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top