计算日历期间内多个起止记录之间的天数

时间:2014-07-01 21:14:31

标签: sql sql-server date

活动可以在给定时间段内开始和停止0次或更多次。每次执行任何操作时,都会生成一个包含日期和操作的记录 - 我将调用操作'Activate(A)'和'Deactivate(D)'。我需要总结一个月内“活跃”天数的总和。我想用一种简单的方法来处理异常和特殊情况。我必须在tsql中这样做。

这是我到目前为止采用的程序方法:

  1. 在此期间是否有开始或停止事件? a)如果否,则查找该时间段之前的最新事件    i)如果该事件是开始,则该时段的所有日期都是活动的   ii)如果事件是停止,则该期间没有活动天数  iii)完成 b)如果是......那么老鼠的程序检查和if-thens。
  2. 像往常一样,我想了解其他人会如何看待这个问题,而不是仅仅开始编写一个例程来按时间顺序对记录进行排序并循环遍历它们。

    典型的数据集:

    6/11/2014  A
    6/20/2014  D
    6/24/2014  A
    6/26/2014  D
    6/29/2014  A
    

    此处,感兴趣的时段是6月,第一个操作被激活 - 因此活动在6月11日之前处于非活动状态。同样,在6月29日,事情再次变为活跃状态,因此本月剩余时间被视为活动状态。在D和A日期使用datediff()函数,我得到9 + 2,并且该月的最后一天总共有12个活动日。

    同样,对于一段时间的数据集,可能有0个或更多记录。

    当然,数据可能看起来像这样:

    6/11/2014  D
    6/20/2014  A
    6/24/2014  D
    6/26/2014  A
    6/29/2014  D
    

    此处,活动在6月11日停用时处于“活动状态”。简单的约会()'(D - A)日期给了我额外的4 + 3天,总共17天。

    我害怕如果我选择,SORT然后做什么我会绕着轴缠绕。我不知道其他人会采取什么样的方式。

1 个答案:

答案 0 :(得分:4)

此查询将为您提供当天相应事件的给定时间段的所有日期:

SQL Fiddle

MS SQL Server 2008架构设置

CREATE TABLE Table1
    ([dt] date, [event] varchar(1))
;

INSERT INTO Table1
    ([dt], [event])
VALUES
    ('2014-06-11', 'A'),
    ('2014-06-20', 'D'),
    ('2014-06-24', 'A'),
    ('2014-06-26', 'D'),
    ('2014-06-29', 'A')
;

查询1

declare @start date, @end date
select @start = '2014-06-01', @end = '2014-06-30'
;with dates as (
  SELECT @start AS d, (SELECT TOP 1 CASE WHEN event = 'A' THEN 'D' ELSE 'A' END FROM Table1 ORDER BY dt) AS e
  UNION ALL 
  SELECT dateadd(day, 1, d), COALESCE((SELECT event FROM Table1 WHERE dt = dateadd(day, 1, dates.d)), dates.e)
  FROM dates 
  WHERE dates.d < @end)
select * from dates
OPTION (MAXRECURSION 0)

<强> Results

|          D | E |
|------------|---|
| 2014-06-01 | D |
| 2014-06-02 | D |
| 2014-06-03 | D |
| 2014-06-04 | D |
| 2014-06-05 | D |
| 2014-06-06 | D |
| 2014-06-07 | D |
| 2014-06-08 | D |
| 2014-06-09 | D |
| 2014-06-10 | D |
| 2014-06-11 | A |
| 2014-06-12 | A |
| 2014-06-13 | A |
| 2014-06-14 | A |
| 2014-06-15 | A |
| 2014-06-16 | A |
| 2014-06-17 | A |
| 2014-06-18 | A |
| 2014-06-19 | A |
| 2014-06-20 | D |
| 2014-06-21 | D |
| 2014-06-22 | D |
| 2014-06-23 | D |
| 2014-06-24 | A |
| 2014-06-25 | A |
| 2014-06-26 | D |
| 2014-06-27 | D |
| 2014-06-28 | D |
| 2014-06-29 | A |
| 2014-06-30 | A |

使用上面的查询,您可以轻松地生成计数查询,如下所示:

declare @start date, @end date
select @start = '2014-06-01', @end = '2014-06-30'
;with dates as (
  SELECT @start AS d, (SELECT TOP 1 CASE WHEN event = 'A' THEN 'D' ELSE 'A' END FROM Table1 ORDER BY dt) AS e
  UNION ALL 
  SELECT dateadd(day, 1, d), COALESCE((SELECT event FROM Table1 WHERE dt = dateadd(day, 1, dates.d)), dates.e)
  FROM dates 
  WHERE dates.d < @end)
select e, count(*) from dates GROUP BY e
OPTION (MAXRECURSION 0)

<强>结果:

| E | COLUMN_1 |
|---|----------|
| A |       13 |
| D |       17 |

或者像这样:

declare @start date, @end date
select @start = '2014-06-01', @end = '2014-06-30'
;with dates as (
  SELECT @start AS d, (SELECT TOP 1 CASE WHEN event = 'A' THEN 'D' ELSE 'A' END FROM Table1 ORDER BY dt) AS e
  UNION ALL 
  SELECT dateadd(day, 1, d), COALESCE((SELECT event FROM Table1 WHERE dt = dateadd(day, 1, dates.d)), dates.e)
  FROM dates 
  WHERE dates.d < @end)
select 
sum(case when e='A' THEN 1 ELSE 0 END) as A_days,
sum(case when e='D' THEN 1 ELSE 0 END) as D_days
from dates
OPTION (MAXRECURSION 0)

<强>结果:

| A_DAYS | D_DAYS |
|--------|--------|
|     13 |     17 |