Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/sql/78.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/date/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
如何在SQL中识别连续日期组?_Sql_Date_Gaps And Islands - Fatal编程技术网

如何在SQL中识别连续日期组?

如何在SQL中识别连续日期组?,sql,date,gaps-and-islands,Sql,Date,Gaps And Islands,我正试图写一个函数来识别日期组,并测量组的大小 select name, date, dateadd(d, - row_number() over (partition by name order by date), date) as val from t 到目前为止,我一直在用Python按程序进行这项工作,但我想将其转移到SQL中 例如,列表 Bill 01/01/2011 Bill 02/01/2011 Bill 03/01/2011 Bill 05/01/2011

我正试图写一个函数来识别日期组,并测量组的大小

select name, date,
       dateadd(d, - row_number() over (partition by name order by date), date) as val
from t
到目前为止,我一直在用Python按程序进行这项工作,但我想将其转移到SQL中

例如,列表

Bill 01/01/2011 
Bill 02/01/2011 
Bill 03/01/2011 
Bill 05/01/2011 
Bill 07/01/2011 
应输出到新表中,如下所示:

Bill 01/01/2011  3 
Bill 02/01/2011  3 
Bill 03/01/2011  3 
Bill 05/01/2011  1 
Bill 07/01/2011  1

理想情况下,这也应该能够考虑到周末和公共假日——我表格中的日期总是周一至周五(我想我可以通过制作一个新的工作日表格并按顺序编号来解决这个问题)。有人建议我试试CTE。我对这个很陌生,所以我很感激任何人能提供的指导!谢谢。

您可以通过巧妙地应用窗口功能来实现这一点。考虑以下事项:

select name, date, row_number() over (partition by name order by date)
from t
这将添加一个行号,在您的示例中,行号仅为1、2、3、4、5。现在,取日期的差值,就得到了组的常量值

select name, date,
       dateadd(d, - row_number() over (partition by name order by date), date) as val
from t
最后,您需要顺序中的组数。我还将添加一个组标识符(例如,用于区分最后两个)


不知怎的,我错过了关于工作日和假日的部分。这个解决方案不能解决那个问题

下面的查询考虑了周末和节假日。查询中有一个包含动态假日的规定,不过为了使查询更清晰,我只是将假日具体化为一个实际的表

CREATE TABLE tx
    (n varchar(4), d date);

INSERT INTO tx
    (n, d)
VALUES
    ('Bill', '2006-12-29'), -- Friday    
    -- 2006-12-30 is Saturday
    -- 2006-12-31 is Sunday

    -- 2007-01-01 is New Year's Holiday    
    ('Bill', '2007-01-02'), -- Tuesday
    ('Bill', '2007-01-03'), -- Wednesday
    ('Bill', '2007-01-04'), -- Thursday
    ('Bill', '2007-01-05'), -- Friday    
    -- 2007-01-06 is Saturday
    -- 2007-01-07 is Sunday

    ('Bill', '2007-01-08'), -- Monday
    ('Bill', '2007-01-09'), -- Tuesday

    ('Bill', '2012-07-09'), -- Monday
    ('Bill', '2012-07-10'), -- Tuesday
    ('Bill', '2012-07-11'); -- Wednesday

create table holiday(d date);
insert into holiday(d) values
('2007-01-01');


/* query should return 7 consecutive good 
   attendance(from December 29 2006 to January 9 2007) */    
/* and 3 consecutive attendance from July 7 2012 to July 11 2012. */
查询:

with first_date as
(
    -- get the monday of the earliest date
    select dateadd( ww, datediff(ww,0,min(d)), 0 ) as first_date 
    from tx 
)
,shifted as
(
    select 
        tx.n, tx.d,                     
        diff = datediff(day, fd.first_date, tx.d) 
                   - (datediff(day, fd.first_date, tx.d)/7 * 2)             
    from tx
    cross join first_date fd
    union
    select 
        xxx.n, h.d,             
        diff = datediff(day, fd.first_date, h.d) 
                   - (datediff(day, fd.first_date, h.d)/7 * 2) 
    from holiday h 
    cross join first_date fd
    cross join (select distinct n from tx) as xxx
)
,grouped as
(
    select *, grp = diff - row_number() over(partition by n order by d)
    from shifted
)
select 
    d, n, dense_rank() over (partition by n order by grp) as nth_streak
    ,count(*) over (partition by n, grp) as streak
from grouped
where d not in (select d from holiday)  -- remove the holidays
输出:

|          D |    N | NTH_STREAK | STREAK |
-------------------------------------------
| 2006-12-29 | Bill |          1 |      7 |
| 2007-01-02 | Bill |          1 |      7 |
| 2007-01-03 | Bill |          1 |      7 |
| 2007-01-04 | Bill |          1 |      7 |
| 2007-01-05 | Bill |          1 |      7 |
| 2007-01-08 | Bill |          1 |      7 |
| 2007-01-09 | Bill |          1 |      7 |
| 2012-07-09 | Bill |          2 |      3 |
| 2012-07-10 | Bill |          2 |      3 |
| 2012-07-11 | Bill |          2 |      3 |
现场测试:

查询的主要逻辑是将所有日期向后移两天。将日期除以7,再乘以2,然后从原始数字中减去。例如,如果给定日期落在15日,则计算为15/7*2==4;然后从原始数字中减去4,15-4==11。15日将成为第11天。同样地,第八天变成了第六天;8-(8/7*2)=6

将计算应用于所有工作日数将产生以下值:

 1  2  3  4  5    
 6  7  8  9 10    
11
对于假期,您需要在出勤率上对它们进行定位,这样就可以很容易地确定出勤率,然后将它们从最终查询中删除。上述出席人数产生了11个连续良好的出席人数


查询逻辑在这里的详细解释:

您使用的是什么RDBMS?SQL只是一种语言。您如何识别假日?如果您希望能够考虑周末和假日,您的想法是保存一个日期表-它通常被称为“日历文件”(或“表”),并且有很多额外用途;除其他事项外,会计日期(即会计年度期间、期间日期)。如果你的公司还没有,那就去创建吧——到处都有示例脚本。当你说“周末和公共假日账户”时,这是什么意思?这是否意味着“连续”天数不计算(即,允许间隔)?或者那些日子会自动产生间隔?很好的解决方案-你可能想要处理重复的日期,尽管要求不明确。如果你想问另一个关于重复日期的问题,我很乐意回答。这不是最初问题的一部分。这很容易成为我在互联网上读到的最美的东西。谢谢你,迈克尔。
 1  2  3  4  5    
 6  7  8  9 10    
11