我需要一个查询,它将单个日期行(不是necesarilly连续)与考虑到对象id的间隔相加。
我有一个select查询,它返回以下数据
id date
9465 12/12/20
9465 12/12/21
9465 12/12/22
9465 12/12/25
9465 12/12/26
9466 12/12/21
9466 12/12/22
9466 12/12/23
9466 12/12/24
9466 12/12/25
9466 12/12/27
我需要一个查询,使用上面作为子查询将输出如下数据:
id date_from date_till
9465 12/12/20 12/12/22
9465 12/12/25 12/12/26
9466 12/12/21 12/12/25
9466 12/12/27 12/12/27
答案 0 :(得分:3)
我们可以通过几个分析来实现这一目标:
SQL> alter session set nls_date_format='yy/mm/dd';
Session altered.
SQL> select id, min(val) date_from, max(val) date_till
2 from (select id, val, max(grp) over(partition by id order by val) grp
3 from (select id, val, lag(val, 1) over(partition by id order by val),
4 case
5 when lag(val, 1) over(partition by id order by val) < val - 1 then
6 row_number() over(partition by id order by val)
7 when row_number() over(partition by id order by val) = 1 then
8 1
9 end grp
10 from mytab))
11 group by id, grp
12 order by id, date_from
13 /
ID DATE_FRO DATE_TIL
---------- -------- --------
9465 12/12/20 12/12/22
9465 12/12/25 12/12/26
9466 12/12/21 12/12/25
9466 12/12/27 12/12/27
即。首先,我们将结果集分成组,其中组被定义为给定ID的有余日期。我们通过检查先前的日期并查看其是否&lt;当前行日期 - 1 lag(val, 1) over(partition by id order by val)
SQL> select id, val, lag(val, 1) over(partition by id order by val),
2 case
3 when lag(val, 1) over(partition by id order by val) < val - 1 then
4 row_number() over(partition by id order by val)
5 when row_number() over(partition by id order by val) = 1 then
6 1
7 end grp
8 from mytab
9 /
ID VAL LAG(VAL, GRP
---------- -------- -------- ----------
9465 12/12/20 1
9465 12/12/21 12/12/20
9465 12/12/22 12/12/21
9465 12/12/25 12/12/22 4
9465 12/12/26 12/12/25
9466 12/12/21 1
9466 12/12/22 12/12/21
9466 12/12/23 12/12/22
9466 12/12/24 12/12/23
9466 12/12/25 12/12/24
9466 12/12/27 12/12/25 6
11 rows selected.
我们需要填写下一个空白,以便空白与之前的非空组相关联。即我们对此max(grp) over(partition by id order by val)
应用max(),这里的顺序意味着我们只获取到达该点的最大行,而不是整个集合中的最大行。
SQL> select id, val, max(grp) over(partition by id order by val) grp
2 from (select id, val, lag(val, 1) over(partition by id order by val),
3 case
4 when lag(val, 1) over(partition by id order by val) < val - 1 then
5 row_number() over(partition by id order by val)
6 when row_number() over(partition by id order by val) = 1 then
7 1
8 end grp
9 from mytab)
10 /
ID VAL GRP
---------- -------- ----------
9465 12/12/20 1
9465 12/12/21 1
9465 12/12/22 1
9465 12/12/25 4
9465 12/12/26 4
9466 12/12/21 1
9466 12/12/22 1
9466 12/12/23 1
9466 12/12/24 1
9466 12/12/25 1
9466 12/12/27 6
11 rows selected.
现在应用一个简单的组(id,grp),为每个id +组取min()和max()。
答案 1 :(得分:2)
我喜欢用一个使用anlytic函数的小技巧来解决这个问题。如果我们枚举每一行,然后从日期中减去该值,那么日期对于事物的顺序是恒定的。这就是“群组”ID。然后这是一个简单的聚合问题:
select id, min(date) as date_from, max(date) as date_to
from (select (date - row_number() over (partition by id order by date)) as groupid,
t.*
from t
)
group by id, groupid
整体陈述也非常简单。
我通常使用分析函数。但是,以下内容可能适用于Oracle,至少对于日期算术有效的数据集是这样的:
select id, min(date) as date_from, max(date) as date_to
from (select (date - rownum) as groupid,
t.*
from t
order by id, date
)
group by id, groupid
答案 2 :(得分:0)
这被称为“岛屿”问题。以下是基于Oracle的解决方案的方法: