Pergunta

Eu tenho uma tabela pai com entradas para documentos e eu tenho uma tabela de histórico que registra uma entrada de auditoria cada vez que um usuário acessa um dos documentos.

Eu estou escrevendo uma consulta de pesquisa para retornar uma lista de documentos (filtrado por vários critérios) com a mais recente identificação de usuário para acessar cada documento retornado no conjunto de resultados.

Assim, para


    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

eu estaria olhando para obter um retorno de minha pesquisa como


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

Posso facilmente fazer isso com uma consulta SQL e uma junção entre as duas tabelas?

Foi útil?

Solução

Revisando o que Andy White produziu, e substituição de colchetes (notação MS SQL Server) com o DB2 (e padrão ISO SQL) "identificadores delimitados":

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

Eu não estou absolutamente certo se "timestamp" ou "TIMESTAMP" está correta -., Provavelmente, a última

A vantagem disso é que ele substitui a sub-consulta correlacionada interna na versão de Andy com uma sub-consulta simples não-correlacionados, que tem o potencial para ser (radicalmente?) Mais eficiente.

Outras dicas

Eu não poderia obter o "TENDO MAX (timestamp)" para executar no SQL Server - Eu acho que ter requer uma expressão booleana como "tendo max (timestamp)> 2009-03-05" ou algo assim, o que não faz aplicável neste caso. (Eu poderia estar fazendo algo errado ...)

Aqui está algo que parece funcionar - nota a junção tem 2 condições (não sei se isso é bom ou não):

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
    )

Esta não usa uma junção, mas para algumas consultas como este gosto para inline a selecção para o campo. Se você quiser pegar a situação quando nenhum usuário acessou você pode envolvê-lo com um 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>

Eu acho que deveria ser algo como isto:

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

Isso pode funcionar também:

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 */
Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top