标记记录岛

时间:2021-05-04 10:28:28

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

我有这个数据集:

<头>
ID PrevId NextId 产品 过程 日期
1 NULL 4 产​​品 1 进程A 2021-04-24
2 NULL 3 产​​品 2 进程A 2021-04-24
3 2 5 产​​品 2 进程A 2021-04-24
4 1 7 产​​品 1 进程B 2021-04-26
5 3 6 产​​品 2 进程B 2021-04-24
6 5 NULL 产​​品 2 进程B 2021-04-24
7 4 9 产​​品 1 进程B 2021-04-29
9 7 10 产​​品 1 进程A 2021-05-01
10 9 15 产​​品 1 进程A 2021-05-03
15 10 19 产​​品 1 进程A 2021-05-04
19 15 NULL 产​​品 1 进程C 2021-05-05

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

<头>
ID PrevId NextId 产品 过程 日期 标签
1 NULL 4 产​​品 1 进程A 2021-04-24 1
4 1 7 产​​品 1 进程B 2021-04-26 2
7 4 9 产​​品 1 进程B 2021-04-29 2
9 7 10 产​​品 1 进程A 2021-05-01 3
10 9 15 产​​品 1 进程A 2021-05-03 3
15 10 19 产​​品 1 进程A 2021-05-04 3
19 15 NULL 产​​品 1 进程C 2021-05-05 4

一个产品要经历多个过程-es,并且可以多次经历同一个过程。

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

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

2 个答案:

答案 0 :(得分:2)

您可以使用 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 是一个 db<>fiddle。

答案 1 :(得分:1)

如果您不必验证 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]
相关问题