【问题标题】:Tag islands of records标记记录岛
【发布时间】:2021-05-04 10:28:28
【问题描述】:

我有这个数据集:

Id PrevId NextId Product Process Date
1 NULL 4 Product 1 Process A 2021-04-24
2 NULL 3 Product 2 Process A 2021-04-24
3 2 5 Product 2 Process A 2021-04-24
4 1 7 Product 1 Process B 2021-04-26
5 3 6 Product 2 Process B 2021-04-24
6 5 NULL Product 2 Process B 2021-04-24
7 4 9 Product 1 Process B 2021-04-29
9 7 10 Product 1 Process A 2021-05-01
10 9 15 Product 1 Process A 2021-05-03
15 10 19 Product 1 Process A 2021-05-04
19 15 NULL Product 1 Process C 2021-05-05

每个产品,我需要标记具有相同流程的连续/孤岛记录,例如:

Id PrevId NextId Product Process Date Tag
1 NULL 4 Product 1 Process A 2021-04-24 1
4 1 7 Product 1 Process B 2021-04-26 2
7 4 9 Product 1 Process B 2021-04-29 2
9 7 10 Product 1 Process A 2021-05-01 3
10 9 15 Product 1 Process A 2021-05-03 3
15 10 19 Product 1 Process A 2021-05-04 3
19 15 NULL Product 1 Process C 2021-05-05 4

一个产品要经过多个流程-es,并且可以不止一次地经过同一个流程。

我基本上需要生成 Tag 列,其背后的逻辑是将具有相同 Process 的连续记录组合在一起,但需要注意的是相同的进程可以出现在更下方,但应被视为一个新组。

我已经尝试过基本的窗口函数(ROW_NUMBERDENSE_RANK),但问题是这些函数计数分区内,而不是分区。 p>

【问题讨论】:

    标签: sql sql-server gaps-and-islands


    【解决方案1】:

    您可以使用lag() 来确定值相同的位置。然后是累积和:

    select t.*,
           1 + sum(case when process = prev_process then 0 else 1 end) over (partition by producct order by id) as tag
    from (select t.*,
                 lag(process) over (partition by product order by id) as prev_process
          from t
         ) t;
    

    Here 是一个 dbfiddle。

    【讨论】:

    • 好像有点不对劲,请看这个fiddle
    • @JohnMarkGabrielCaguicla 。 . .添加1 确实没有明显的偏差,但我修改了答案。
    • 它不只是减 1,具有不同 Process 的记录被组合在一起。请参阅我在之前评论中链接的小提琴。
    • @JohnMarkGabrielCaguicla 。 . .我懂了。答案中有错字。我修正了错字并认为这是最简单的答案。
    【解决方案2】:

    如果您不必验证 prevId 和 nextId(也就是说,如果您的数据已经正确排序),您可以尝试以下操作:

    WITH cte AS(
    SELECT *
           , ROW_NUMBER() OVER (PARTITION BY Product ORDER BY [Date]) x
           , DENSE_RANK() OVER (PARTITION BY Product, Process ORDER BY [Date]) y
      FROM T1
      WHERE product = 'Product 1'
    ),
    cteTag AS(
    SELECT Id, PrevId, NextId, Product, Process, [Date], x-y AS Tag_
      FROM cte
    )
    SELECT Id, PrevId, NextId, Product, Process, [Date], DENSE_RANK() OVER (PARTITION BY Product ORDER BY Tag_) AS Tag
      FROM cteTag
    ORDER BY [Date]
    

    【讨论】:

    • 谢谢,这正是我所需要的。 ROW_NUMBER + x-y 的技巧非常聪明。
    猜你喜欢
    • 2012-07-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-06-22
    • 2017-08-17
    相关资源
    最近更新 更多