[英]Merge lines over timespan in SCD2 table
我的下表來自 SCD2 表。 從這個源表中,我只選擇了幾列,這導致幾行看起來完全相似。 我想刪除不必要的行,那些包含相同數據的行,並讓 ValidFrom 列顯示第一個值,而 ValidTo 列顯示“時間跨度組”中的最后一個值。
源數據:
| Item | Color | ValidFrom | ValidTo |
| -------- | ---------- | ------------- | ---------- |
| Ball | Red | 2020-01-01 | 2020-03-24 |
| Ball | Blue | 2020-03-25 | 2020-04-12 |
| Ball | Blue | 2020-04-13 | 2020-05-07 |
| Ball | Blue | 2020-05-08 | 2020-11-14 |
| Ball | Red | 2020-11-15 | 9999-12-31 |
| Doll | Yellow | 2020-01-01 | 2020-03-24 |
| Doll | Green | 2020-03-25 | 2020-04-12 |
| Doll | Green | 2020-04-13 | 2020-05-07 |
| Doll | Green | 2020-05-08 | 2020-11-14 |
| Doll | Pink | 2020-11-15 | 9999-12-31 |
我想要完成的是:
| Item | Color | ValidFrom | ValidTo |
| -------- | ---------- | ------------- | ---------- |
| Ball | Red | 2020-01-01 | 2020-03-24 |
| Ball | Blue | 2020-03-25 | 2020-11-14 |
| Ball | Red | 2020-11-15 | 9999-12-31 |
| Doll | Yellow | 2020-01-01 | 2020-03-24 |
| Doll | Green | 2020-03-25 | 2020-11-14 |
| Doll | Pink | 2020-11-15 | 9999-12-31 |
請注意,項目球最初的顏色是紅色,然后是藍色,然后又變回紅色。 根據我所學到的,這使事情變得更加復雜。
謝謝你的幫助。
這是孤島和差距問題。
您可以使用解析 function 如下:
Select item, color,
min(validfrom) as validfrom,
Max(validto) as validto
From
(Select t.*,
Sum(case when lged between validfrom and validto then 0 else 1 end)
over (partition by item, color order by validfrom) as sm
From
(Select t.*,
Lag(validto) over (partition by item, color order by validfrom) as lged
From t) t) t
Group by item, color, sm
這確實是一個間隙和島嶼問題,其中島嶼是具有相同項目和顏色的相鄰記錄。
在這里,我建議使用行號之間的差異來定義組。 這僅涉及一層嵌套,而不是使用lag()
時的兩層,因此它應該是最有效的選擇:
select item, color, min(validfrom) as validfrom, max(validto) as validto
from (
select t.*,
row_number() over(order by validfrom) as rn1,
row_number() over(partition by item, color order by validfrom) as rn2
from mytable t
) t
group by item, color, rn1 - rn2
你的數據很規律。 您似乎只想組合沒有重疊或間隙的相鄰平鋪記錄。 然而,以下處理差距和更普遍的重疊:
select item, color, min(validfrom), max(validto)
from (select t.*,
sum(case when prev_validto >= dateadd(day, -1, validfrom)
then 0 else 1
end) over (partition by item order by validfrom) as grp
from (select t.*,
lag(validto) over (partition by item, color order by validfrom) as prev_validto
from t
) t
) t
group by item, color, grp;
您正在尋找原始數據中的行島,其中“島”具有相同的項目、顏色和相鄰日期。 這通過查看相同項目和顏色的前一行來確定島嶼的開始位置。 如果沒有這樣的行或該行在當前行開始之前結束,則當前行是島的開始。
然后grp
是“島嶼起點”的累積總和,可用於聚合並獲得最終結果。
您的特定數據非常有限 - 完美地平鋪了一行在下一行開始的前一天結束。 您可以使用left join
做一些非常相似的事情:
select item, color, min(validfrom), max(validto)
from (select t.*,
sum(case when tprev.color is null then 1 else 0
end) over (partition by t.item order by t.validfrom) as grp
from t left join
t tprev
on tprev.item = t.item and
tprev.color = t.color and
tprev.validto = dateadd(day, -1, t.validfrom)
) t
group by item, color, grp
order by item, min(validfrom);
這是一個說明這兩種方法的 db<>fiddle
由於行之間沒有間隙或重疊,因此此查詢就足夠了
select item, color,
min(validfrom) as ValidFrom,
max(validto) as ValidTo
from tTable
group by item, color
order by item, ValidFrom;
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.