【问题标题】:Subquery to return the latest entry for each parent ID子查询返回每个父 ID 的最新条目
【发布时间】:2009-03-09 04:54:55
【问题描述】:

我有一个包含文档条目的父表,我有一个历史表,每次用户访问其中一个文档时都会记录一个审核条目。

我正在编写一个搜索查询来返回一个文档列表(按各种标准过滤),其中包含最新的用户 ID,以访问结果集中返回的每个文档。

因此对于


    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

我希望从我的搜索中获得回报,例如


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

我可以通过一个 SQL 查询和两个表之间的连接轻松地做到这一点吗?

【问题讨论】:

    标签: sql db2


    【解决方案1】:

    修改 Andy White 产生的内容,并将方括号(MS SQL Server 表示法)替换为 DB2(和 ISO 标准 SQL)“分隔标识符”:

    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
    

    我不确定“timestamp”或“TIMESTAMP”是否正确 - 可能是后者。

    这样做的好处是它用更简单的非相关子查询替换了 Andy 版本中的内部相关子查询,这有可能(从根本上?)更高效。

    【讨论】:

      【解决方案2】:

      我无法让“HAVING MAX(TIMESTAMP)”在 SQL Server 中运行 - 我猜想需要一个布尔表达式,例如“有 max(TIMESTAMP) > 2009-03-05”或其他东西,它没有适用于这种情况。 (我可能做错了什么……)

      这似乎可行 - 请注意连接有 2 个条件(不确定这是否好用):

      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
          )
      

      【讨论】:

      • 我想我可以在内部查询中使用 max(TIMESTAMP),而不是 select top 1 ... order by [TIMESTAMP] desc
      • 你应该去掉 MS SQL Server 的方括号,或者用 DB2 等效符号“TIMESTAMP”替换它们。
      • 抱歉……我只知道这些
      • 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)
      • 我不得不从 Informix 映射到 DB2 - 并行但不同的问题。 :D
      【解决方案3】:

      这不使用连接,但对于像这样的一些查询,我喜欢内联字段的选择。如果你想捕捉没有用户访问的情况,你可以用 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>
      

      【讨论】:

        【解决方案4】:

        我觉得应该是这样的:

        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
        

        这也可能有效:

        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 )
        

        【讨论】:

        • 你需要一个 LEFT OUTER JOIN 来获得所需输出的最后三行。
        • 我无法让 max(timestamp) 在 SQL 服务器上工作 - 这对其他数据库也有效吗?
        • 您可能需要:GROUP BY DOC_ID、USER_ID,并且您需要修复 HAVING 子句...
        • @Jonathan - 你知道在这种情况下你是否可以使用 have 吗?我有点搞砸了,但根本无法/必须为此工作。我是一个 SQL 菜鸟,如果你知道的话,我很想看看怎么做。
        【解决方案5】:
        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 */
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2011-02-08
          • 1970-01-01
          • 1970-01-01
          • 2018-05-08
          • 2015-06-16
          相关资源
          最近更新 更多