SQL 服务器 - 按标志汇总日期

SQL Server - summarize dates by a flag

我正在使用 SQL Server 2008(尽管如果需要可以访问 SQL 2017)并且 table 是这样的:

DECLARE @tbl TABLE (recdate DATE, myflag BIT)

table 有一个范围内所有日期的行,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 更改时,它都会创建一个新行并且前一行设置了结束日期(如果有意义的话)

我确定有一个非常明显的方法可以做到这一点,但我准备好 bash 我的头靠在墙上..我已经来回选择和子选择和插入和更新临时 tables,甚至尝试游标(我知道!但它是一次性查询)

这是一个缺口和孤岛问题。为此,您可以使用不同的行号:

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;

这和第一个版本的逻辑基本一样