sql-server - 计算值大于 0 的连续天数

标签 sql-server rank gaps-and-islands

使用 SQL Server 2012,我尝试创建一个查询,该查询为我提供气候数据库中前 10 个最长的湿润(或干燥)周期。

我的临时表提供以下数据输出:

select monthid as [id], date, rain_today 
from #raindays
order by monthid asc, date asc

输出:

id  date            rain_today
-------------------------------
1   24 Dec 2014     2.4
1   25 Dec 2014     0
1   26 Dec 2014     8.7
1   27 Dec 2014     1.8
1   28 Dec 2014     0.3
1   29 Dec 2014     0
1   30 Dec 2014     0
1   31 Dec 2014     0.3
2   01 Jan 2015     0.3
2   02 Jan 2015     0.3
2   03 Jan 2015     18.3
2   04 Jan 2015     0.3

等等。等等

我想返回一个排名表,该表将计算 rain_today > 0(或 rain_today = 0)的时间段,即:

Rank Start_Date   End_Date    Wet Period
----------------------------------------
1    31 Dec 2014  04 Jan 2015 5
2    26 Dec 2014  28 Dec 2014 3

...

我从审查其他类似查询中得到的最接近的结果如下(这是针对干燥天气的):

 select 
     #raindays.monthid as id,
     min(#raindays.date) as [FirstDryDay],
     max(#raindays.date) as [LatestDryDay],
     count(*) as countdays
 from 
     (select 
          monthid, 
          coalesce(max(case 
                          when rain_today > '0' 
                             then #raindays.date end), '19000101') as latestdry
     from 
         #raindays
     group by 
         monthid) g
join 
    #raindays on #raindays.monthid = g.monthid
              and #raindays.date > g.latestdry
group by 
    #raindays.monthid
order by 
    countdays desc

输出:

id  FirstDryDay     LatestDryDay    countdays
-----------------------------------------------
23  21 Oct 2016     31 Oct 2016     11
21  23 Aug 2016     31 Aug 2016     9
**15    23 Feb 2016     29 Feb 2016     7**
10  25 Sep 2015     30 Sep 2015     6
8   28 Jul 2015     31 Jul 2015     4
24  28 Nov 2016     30 Nov 2016     3
29  29 Apr 2017     30 Apr 2017     2
30  30 May 2017     31 May 2017     2
31  29 Jun 2017     30 Jun 2017     2
20  30 Jul 2016     31 Jul 2016     2
7   29 Jun 2015     30 Jun 2015     2
5   30 Apr 2015     30 Apr 2015     1
11  31 Oct 2015     31 Oct 2015     1
17  30 Apr 2016     30 Apr 2016     1
22  30 Sep 2016     30 Sep 2016     1

正如您所看到的,我真的不想按 id 进行分组,因为我希望能够跨越不同的月份,并且错过了该月早些时候发生的其他时期。实际计数似乎工作正常,检查上面突出显示的周期:

id  date    rain_today
15  22 Feb 2016     3.9
15  23 Feb 2016     0
15  24 Feb 2016     0
15  25 Feb 2016     0
15  26 Feb 2016     0
15  27 Feb 2016     0
15  28 Feb 2016     0
15  29 Feb 2016     0
16  01 Mar 2016     3

预先感谢您的帮助!

最佳答案

这就是你想要的吗???

IF OBJECT_ID('tempdb..#TestData', 'U') IS NOT NULL 
DROP TABLE #TestData;

CREATE TABLE #TestData (
    id INT NOT NULL ,
    [Date] DATE NOT NULL,
    Rain_Today DECIMAL(9,2) NOT NULL 
    );

INSERT #TestData (id, Date, Rain_Today) VALUES 
    (1, '24 Dec 2014', 2.4),
    (1, '25 Dec 2014', 0),
    (1, '26 Dec 2014', 8.7),
    (1, '27 Dec 2014', 1.8),
    (1, '28 Dec 2014', 0.3),
    (1, '29 Dec 2014', 0),
    (1, '30 Dec 2014', 0),
    (1, '31 Dec 2014', 0.3),
    (2, '01 Jan 2015', 0.3),
    (2, '02 Jan 2015', 0.3),
    (2, '03 Jan 2015', 18.3),
    (2, '04 Jan 2015', 0.3);

--======================================

WITH 
    cte_AddRankGroup AS (
        SELECT 
            td.id,
            td.Date,
            td.Rain_Today,
            hr.HasRain,
            RankGroup = DENSE_RANK() OVER (PARTITION BY td.id ORDER BY td.Date) -
                DENSE_RANK() OVER (PARTITION BY td.id, hr.HasRain ORDER BY td.Date)
        FROM 
            #TestData td
            CROSS APPLY ( VALUES (IIF(td.Rain_Today = 0, 0, 1)) ) hr (HasRain)
        )
SELECT 
    arg.id,
    BegDate = MIN(arg.Date),
    EndDate = MAX(arg.Date),
    WetPeriod = IIF(arg.HasRain = 1, 'Wet', 'Dry'),
    ConsecutiveDays = COUNT(1)
FROM 
    cte_AddRankGroup arg
GROUP BY 
    arg.id,
    arg.HasRain,
    arg.RankGroup
ORDER BY 
    arg.id,
    MIN(arg.Date);

结果...

id          BegDate     EndDate     WetPeriod ConsecutiveDays
----------- ----------  ----------  --------- ---------------
1           2014-12-24  2014-12-24  Wet       1
1           2014-12-25  2014-12-25  Dry       1
1           2014-12-26  2014-12-28  Wet       3
1           2014-12-29  2014-12-30  Dry       2
1           2014-12-31  2014-12-31  Wet       1
2           2015-01-01  2015-01-04  Wet       4

编辑:使用 CASE 表达式代替 IIF 的代码版本...

--======================================

WITH 
    cte_AddRankGroup AS (
        SELECT 
            td.id,
            td.Date,
            td.Rain_Today,
            hr.HasRain,
            RankGroup = DENSE_RANK() OVER (PARTITION BY td.id ORDER BY td.Date) -
                DENSE_RANK() OVER (PARTITION BY td.id, hr.HasRain ORDER BY td.Date)
        FROM 
            #TestData td
            CROSS APPLY ( VALUES (CASE WHEN td.Rain_Today = 0 THEN 0 ELSE 1 END) ) hr (HasRain)
        )
SELECT top 10
    arg.id,
    BegDate = MIN(arg.Date),
    EndDate = MAX(arg.Date),
    WetPeriod = CASE WHEN arg.HasRain = 1 THEN 'Wet' ELSE 'Dry' END,
    ConsecutiveDays = COUNT(1)
FROM 
    cte_AddRankGroup arg
WHERE 
    arg.HasRain = '0' -- Top 10 Dry
    --arg.HasRain = '1' -- Top 10 Wet
GROUP BY 
    arg.id,
    arg.HasRain,
    arg.RankGroup
ORDER BY 
    ConsecutiveDays desc, MIN(arg.Date);

修改原始脚本以按每个时期类型生成前 10 名,这是我的最终目标(输出来自完整数据集):

id  BegDate EndDate WetPeriod   ConsecutiveDays
31  10 Jun 2017     26 Jun 2017     Dry 17
4   02 Mar 2015     14 Mar 2015     Dry 13
5   12 Apr 2015     24 Apr 2015     Dry 13
20  15 Jul 2016     26 Jul 2016     Dry 12
29  01 Apr 2017     11 Apr 2017     Dry 11
26  17 Jan 2017     27 Jan 2017     Dry 11
23  21 Oct 2016     31 Oct 2016     Dry 11
25  01 Dec 2016     09 Dec 2016     Dry 9
21  10 Aug 2016     18 Aug 2016     Dry 9
21  23 Aug 2016     31 Aug 2016     Dry 9

关于sql-server - 计算值大于 0 的连续天数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45308231/

相关文章:

sql-server - 尝试在 SSMS 中重命名数据库/表时,Delete 键不起作用是否正常?

sql-server - SQL Server如何去除表中的重复行

sql-server - Reporting Services 报告 "overprints"的 PDF 呈现文本

r - 获取矩阵条目的等级?

sql - 查找多行中连续日期的开始和结束日期

sql - 按值组的连续日期范围对行进行分组

sql - 存储过程参数值记录

MYSQL 基于多列的Rank

mysql - 在 MySQL 中按组排名

mysql - MYSQL中将日期转换为日期范围---如何处理日期中的间隙