活动可以在给定时间段内开始和停止0次或更多次。每次执行任何操作时,都会生成一个包含日期和操作的记录 - 我将调用操作'Activate(A)'和'Deactivate(D)'。我需要总结一个月内“活跃”天数的总和。我想用一种简单的方法来处理异常和特殊情况。我必须在tsql中这样做。
这是我到目前为止采用的程序方法:
像往常一样,我想了解其他人会如何看待这个问题,而不是仅仅开始编写一个例程来按时间顺序对记录进行排序并循环遍历它们。
典型的数据集:
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然后做什么我会绕着轴缠绕。我不知道其他人会采取什么样的方式。
答案 0 :(得分:4)
此查询将为您提供当天相应事件的给定时间段的所有日期:
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 |