我需要按ID对数据进行分组并找到最大/最小(date_from,date_to)。但是,如果有日期间隔,应该在新的一行。
我有以下数据:
SYS_ID ITEM_ID DATE_FROM DATE_TO
1 1 01.01.2019 20.01.2019
1 1 15.01.2019 10.02.2019
1 1 15.02.2019 20.02.2019
1 1 18.02.2019 10.03.2019
1 1 10.03.2019 22.03.2019
1 2 01.01.2019 10.01.2019
1 2 15.01.2019 25.01.2019
结果应为:
SYS_ID ITEM_ID DATE_FROM DATE_TO
1 1 01.01.2019 10.02.2019
1 1 15.02.2019 22.03.2019
1 2 01.01.2019 10.01.2019
1 2 15.01.2019 25.01.2019
有没有一种方法可以不使用光标?
答案 0 :(得分:3)
使用差距和孤岛方法
实时测试:http://sqlfiddle.com/#!18/0174b/3
with gap_detector as
(
select
sys_id, item_id,
date_from, date_to,
case when
lag(date_to)
over(partition by sys_id, item_id order by date_from) >= date_from
then
0
else
1
end as gap
from tbl
)
, grouper as
(
select
sys_id, item_id,
date_from, date_to,
sum(gap) over(partition by sys_id, item_id order by date_from) as grp
from gap_detector
)
select
sys_id, item_id,
min(date_from) as date_from,
max(date_to) as date_to
from grouper
group by sys_id, item_id, grp
输出:
| sys_id | item_id | date_from | date_to |
|--------|---------|------------|------------|
| 1 | 1 | 2019-01-01 | 2019-02-10 |
| 1 | 1 | 2019-02-15 | 2019-03-22 |
| 1 | 2 | 2019-01-01 | 2019-01-10 |
| 1 | 2 | 2019-01-15 | 2019-01-25 |
首先,我们需要检测前一行(使用lag
)的date_to是否与当前date_from重叠。
请注意,我们有独立的date_from集,即sys_id
+ item_id
组合的前一行(例如1,1)与另一个sys_id
+ { {1}}组合(例如1,2)。因此,item_id
的前一个date_to不是1,2
,而是March 22, 2019
。我们可以通过对NULL
+ sys_id
进行分区来正确识别每个组合的前一行。
上面说的是我们如何确定上一行的date_to是否与当前date_from重叠:
item_id
)。值为1。稍后我们为什么需要1和0。实时测试:http://sqlfiddle.com/#!18/0174b/7
partition by sys_id, item_id
输出:
gap
下一步是通过在间隙标记(1和0)上进行累加总计,将属于彼此的岛分组。通过在with gap_detector as
(
select
sys_id, item_id,
date_from, date_to,
case when
lag(date_to)
over(partition by sys_id, item_id order by date_from) >= date_from
then
0
else
1
end as gap
from tbl
)
select *
from gap_detector
order by sys_id, item_id, date_from
+ | sys_id | item_id | date_from | date_to | gap |
|--------|---------|------------|------------|-----|
| 1 | 1 | 2019-01-01 | 2019-01-20 | 1 |
| 1 | 1 | 2019-01-15 | 2019-02-10 | 0 |
| 1 | 1 | 2019-02-15 | 2019-02-20 | 1 |
| 1 | 1 | 2019-02-18 | 2019-03-10 | 0 |
| 1 | 1 | 2019-03-10 | 2019-03-22 | 0 |
| 1 | 2 | 2019-01-01 | 2019-01-10 | 1 |
| 1 | 2 | 2019-01-15 | 2019-01-25 | 1 |
组合窗口上进行sum(gap)
来完成总计。
sys_id
+ item_id
组合的每个窗口都可以通过对其进行sys_id
即item_id
实时测试:http://sqlfiddle.com/#!18/0174b/12
partition
输出:
partition by sys_id, item_id
最后,既然我们已经能够识别出哪些岛属于彼此(由with gap_detector as
(
select
sys_id, item_id,
date_from, date_to,
case when
lag(date_to)
over(partition by sys_id, item_id order by date_from) >= date_from
then
0
else
1
end as gap
from tbl
)
, grouper as
(
select
sys_id, item_id,
date_from, date_to,
gap,
sum(gap) over(partition by sys_id, item_id order by date_from) as grp
from gap_detector
)
select sys_id, item_id, date_from, date_to, gap, grp
from grouper
表示),那么只需对这些| sys_id | item_id | date_from | date_to | gap | grp |
|--------|---------|------------|------------|-----|-----|
| 1 | 1 | 2019-01-01 | 2019-01-20 | 1 | 1 |
| 1 | 1 | 2019-01-15 | 2019-02-10 | 0 | 1 |
| 1 | 1 | 2019-02-15 | 2019-02-20 | 1 | 2 |
| 1 | 1 | 2019-02-18 | 2019-03-10 | 0 | 2 |
| 1 | 1 | 2019-03-10 | 2019-03-22 | 0 | 2 |
| 1 | 2 | 2019-01-01 | 2019-01-10 | 1 | 1 |
| 1 | 2 | 2019-01-15 | 2019-01-25 | 1 | 2 |
标记执行grp
即可识别在各组(group by
)岛屿上开始date_from和date_to时。
实时测试:http://sqlfiddle.com/#!18/0174b/13
grp
输出:
grp