【问题标题】:Using LEAD (or LAG) in conjunction with a JOIN将 LEAD(或 LAG)与 JOIN 结合使用
【发布时间】:2019-10-03 03:25:38
【问题描述】:

明细表需要从表头中获取列数据,包括前后表头记录的数据。

我尝试过使用 SELECT、JOIN 等的各种组合

不好意思给你看;)

HEADER table

HEADERPK    TIMESTAMP               LOCATION
--------    --------------------    --------
1234        2019–05-22 12:00:00     ABC
3456        2019-08-14 21:30:00     XYZ
7890        2019-10-01 05:00:00     QRS




DETAIL table

DETAILPK    PART        HEADERPK
---------   ---------   --------
2222        ZZZ-100     1234
3333        ZZZ-100     3456
4444        ZZZ-100     7890

预期结果(使用 DETAIL 表)

DETAILPK    PREV_LOCATION   PREV_TIMESTAMP      NEXT_LOCATION   NEXT_TIMESTAMP
--------    -------------   ------------------- -------------   -------------------
3333        ABC     2019–05-22 12:00:00         QRS             2019-10-01 05:00:00

目的是对于给定的 DETAIL 记录,我可以确定之前和之后的 HEADER 记录的时间戳和位置。

我的想法是使用 HEADERPK 加入表,但我不清楚如何为每个细节对标题记录进行排序。

【问题讨论】:

  • 你如何定义“下一个”?
  • 好吧,我不小心漏掉了问题的一部分。对于所有响应者,在我进行更新之前无需提供任何答案。感谢所有这么快回答的人。

标签: sql sql-server


【解决方案1】:

您将需要一个窗口函数和一个子查询。我认为最易读的方法是将 CTE 与所有窗口函数一起使用:

WITH 
    adjacent_headers AS
    (
        SELECT
            headerpk,
            prev_headerpk = LAG(headerpk) OVER (ORDER BY headerpk),
            prev_ts = LAG([timestamp]) OVER (ORDER BY headerpk),
            prev_loc = LAG(location) OVER (ORDER BY headerpk),
            next_headerpk = LEAD(headerpk) OVER (ORDER BY headerpk),
            next_ts = LEAD([timestamp]) OVER (ORDER BY headerpk),
            next_loc = LEAD(location) OVER (ORDER BY headerpk)
        FROM header
    )
SELECT
    detail.detailpk,
    adjacent_headers.prev_loc,
    adjacent_headers.prev_ts,
    adjacent_headers.next_loc,
    adjacent_headers.next_ts
FROM detail
    INNER JOIN adjacent_headers ON
        adjacent_headers.headerpk = detail.headerpk

请注意,这假设您通过对“标题 ID”列进行排序来定义“上一个”和“下一个”标题记录。如果您只想包含相关标头同时包含上一条和下一条记录的详细信息,则可以将其添加到最终查询的 WHERE 子句中。

【讨论】:

    【解决方案2】:

    如果您说要在join 中使用leadlag,则不能这样做。但是如果你只是想在同一个sql语句中使用它们,你可以这样做:

    select      d.detailpk,
                prev_location = lead(h.location) over(order by h.timestamp desc),
                prev_timestamp = lead(h.timestamp) over(order by h.timestamp desc),
                next_location = lag(h.location) over(order by h.timestamp desc),
                next_timestamp = lag(h.timestamp) over(order by h.timestamp desc)
    from        detail d
    join        header h on d.headerpk = h.headerpk
    order by    h.timestamp;
    

    现在,如果您的实际场景有很多字段,您需要获取 leadlag 项,您可以避免很多这样的 over 语句:

    with
    
        offset as (
    
            select      *,
                        prev_headerPk = lead(headerpk) over(order by timestamp),
                        next_headerPk = lag(headerpk) over(order by timestamp)
            from        header
    
        )
    
        select      d.detailpk,
                    prev_location = p.location,
                    prev_timestamp = p.timestamp,
                    next_location = n.location,
                    next_timestamp = n.timestamp
        from        detail d
        left join   offset p on d.headerpk = p.prev_headerPk
        left join   offset n on d.headerpk = n.next_headerPk
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-11-23
      • 1970-01-01
      • 2022-01-08
      • 1970-01-01
      • 2015-03-29
      相关资源
      最近更新 更多