我使用的是SQL Server 2008 (如果需要,可以访问SQL 2017 ),并且有一个如下所示的表:
DECLARE @tbl TABLE (recdate DATE, myflag BIT)
该表包含一个范围内所有日期的行,myflag位将时断时续地变化,如下所示:
recdate | myflag
2017-01-01 | 1
2017-01-02 | 1
2017-01-03 | 1
...
2017-04-03 | 1
2017-04-04 | 0
2017-04-05 | 0
..
2017-05-15 | 0
2017-05-16 | 1
etc.
但我真正需要的是像这样
period_from | period_to | myflag
2017-01-01 | 2017-04-03 | 1
2017-04-04 | 2017-05-15 | 0
2017-05-16 | 2017-05-21 | 1
因此,每次myflag更改时,它都会创建一个新行,并且前一行设置了结束日期(如果有意义的话)
我相信有一种非常明显的方法可以做到这一点,但是我已经准备好用头撞墙了.我在临时表中反复使用selects、subselects、inserts和updates,甚至尝试使用游标(我知道!但这是一次性查询)
发布于 2018-06-06 05:08:06
这是一个缝隙和岛屿问题。为此,您可以使用行号的不同:
select min(recdate) as period_from, max(recdate) as period_to, flag
from (select t.*,
row_number() over (order by recdate) as seqnum,
row_number() over (partition by flag order by recdate) as seqnum_f
from @tbl t
) t
group by (seqnum - seqnum_f), flag;
为什么这样做有点难以用语言来解释。我发现,如果运行子查询,就会发现为什么要查找的组的差异是恒定的。
如果你的日期是连续的,没有间隔,没有重复,也没有时间成分,你可以做稍微简单一点的:
select min(recdate) as period_from, max(recdate) as period_to, flag
from (select t.*,
dateadd(day,
- row_number() over (partition by flag order by recdate
recdate
) as grp
from @tbl t
) t
group by grp, flag;
这基本上与第一个版本的逻辑相同。
https://stackoverflow.com/questions/50708900
复制相似问题