在 SCD2 table 中合并时间跨度的行
Merge lines over timespan in SCD2 table
我有以下 table 来自 SCD2 table。从这个来源 table,我只选择了几列,这导致几行看起来完全相似。我想删除不必要的行,那些包含相同数据的行,并让 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 |
请注意,Item Ball 首先是红色,然后是蓝色,然后又变回红色。根据我的了解,这让事情变得有点复杂。
感谢您的帮助。
这是孤岛和缺口问题
您可以使用如下解析函数:
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);
Here 是一个 db<>fiddle 说明这两种方法
由于行之间没有间隙或重叠,也许这个查询就足够了
select item, color,
min(validfrom) as ValidFrom,
max(validto) as ValidTo
from tTable
group by item, color
order by item, ValidFrom;
我有以下 table 来自 SCD2 table。从这个来源 table,我只选择了几列,这导致几行看起来完全相似。我想删除不必要的行,那些包含相同数据的行,并让 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 |
请注意,Item Ball 首先是红色,然后是蓝色,然后又变回红色。根据我的了解,这让事情变得有点复杂。
感谢您的帮助。
这是孤岛和缺口问题
您可以使用如下解析函数:
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);
Here 是一个 db<>fiddle 说明这两种方法
由于行之间没有间隙或重叠,也许这个查询就足够了
select item, color,
min(validfrom) as ValidFrom,
max(validto) as ValidTo
from tTable
group by item, color
order by item, ValidFrom;