Domanda

Ho una tabella padre con voci per i documenti e ho una tabella cronologica che registra una voce di controllo ogni volta che un utente accede a uno dei documenti.

Sto scrivendo una query di ricerca per restituire un elenco di documenti (filtrati in base a vari criteri) con l'ultimo ID utente per accedere a ciascun documento restituito nel set di risultati.

Quindi per


    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

Cercherei di ottenere un ritorno dalla mia ricerca come


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

Posso farlo facilmente con una query SQL e un join tra le due tabelle?

È stato utile?

Soluzione

Revisione di ciò che Andy White ha prodotto e sostituzione di parentesi quadre (notazione MS SQL Server) con DB2 (e ISO standard ISO) "identificatori delimitati";

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

Non sono assolutamente sicuro che " data / ora " o " TIMESTAMP " è corretto, probabilmente quest'ultimo.

Il vantaggio è che sostituisce la sottoquery correlata interna nella versione di Andy con una sottoquery non correlata più semplice, che ha il potenziale per essere (radicalmente?) più efficiente.

Altri suggerimenti

Non è stato possibile ottenere " HAVING MAX (TIMESTAMP) " per funzionare in SQL Server - Immagino che abbia bisogno di un'espressione booleana come " avendo max (TIMESTAMP) > 2009-03-05 " o qualcosa del genere, che non si applica in questo caso. (Potrei fare qualcosa di sbagliato ...)

Ecco qualcosa che sembra funzionare: nota che il join ha 2 condizioni (non sono sicuro che sia buono o meno):

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
    )

Questo non usa un join, ma per alcune domande come questa mi piace incorporare la selezione per il campo. Se vuoi cogliere la situazione quando nessun utente ha avuto accesso puoi avvolgerla con una 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>

Penso che dovrebbe essere qualcosa del genere:

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

questo potrebbe funzionare anche:

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 */
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top