我在表中有这些数据
_____DateTime____|Variable__|Value
2017/03/29 23:00:00 | Variable1 | 1
2017/03/31 01:00:00 | Variable1 | 0
2017/03/31 02:00:00 | Variable1 | 1
2017/03/31 03:00:00 | Variable1 | 0
2017/03/31 04:00:00 | Variable2 | 1
2017/03/31 23:00:00 | Variable1 | 1
2017/04/01 01:00:00 | Variable1 | 0
我想计算两个日期之间每个变量处于状态1的总持续时间
例如,在Var1 2017/03/31 00:00:00和2017/04/01 00:00:00之间 结果是:
1 hour between 2017/03/31 00:00:00 and 2017/03/31 01:00:00
1 hour between 2017/03/31 02:00:00 and 2017/03/31 03:00:00
1 hour between 2017/03/31 23:00:00 and 2017/04/01 00:00:00
所以我想要Var1的结果应该是3小时
例如,在Var2 2017/03/31 00:00:00和2017/04/01 00:00:00之间 结果是: 2017/03/31 04:00:00至2017/04/01 00:00:00之间1小时(之前没有价值,但因为它变为1我以前认为是0)
所以我想要Var2的结果应该是20小时
变量 | __Time in Value(second)
Variable1 | 180
变量2 | 1200
如果有人可以帮助我。
提前致谢
答案 0 :(得分:1)
对于SQL Server 2012+(由于lead()
和concat()
)
使用堆叠cte生成一个小时表到inner join
子查询,该子查询使用lead()
窗口函数来获取由Variable
分区的状态更改的下一个日期。
要适应以前的版本,请使用outer apply()
为每个变量而不是dt
获取下一个lead()
;和常规字符串连接以及正确的转换,而不是concat()
。
declare @fromdate datetime = '20170331 00:00:00';
declare @thrudate datetime = '20170401 00:00:00';
;with n as (select n from (values(0),(1),(2),(3),(4),(5),(6),(7),(8),(9)) t(n))
, hours as (
select top ((datediff(hour, @fromdate, @thrudate)+1))
[DateHour]=dateadd(hour,(row_number() over (order by (select 1)) -1),@fromdate)
from n as deka cross join n as hecto cross join n as kilo
cross join n as tenK cross join n as hundredK
order by 1
)
select variable, value
, hours = count(h.datehour)
, start_dt = convert(varchar(20),min(h.datehour),120)
, end_dt = convert(varchar(20),end_dt,120)
, txt = concat(
count(h.datehour),' '
, case when count(h.datehour) < 2 then 'hour' else 'hours' end
, ' between '
, convert(varchar(20),min(h.datehour),120)
, ' and '
, convert(varchar(20),end_dt,120)
)
from hours h
inner join (
select
variable
, value
, start_dt = dt
, end_dt = case when coalesce(lead(dt) over (partition by variable order by dt),@thrudate) > @thrudate
then @thrudate
else coalesce(lead(dt) over (partition by variable order by dt),@thrudate)
end
from t
) s
on h.datehour >= s.start_dt
and h.datehour < s.end_dt
where h.datehour >= @fromdate
and h.datehour < @thrudate
and s.value = 1
group by variable, value, start_dt, end_dt
rextester演示:http://rextester.com/ZBWP22523
返回:
+-----------+-------+-------+---------------------+---------------------+--------------------------------------------------------------+
| variable | value | hours | start_dt | end_dt | txt |
+-----------+-------+-------+---------------------+---------------------+--------------------------------------------------------------+
| Variable1 | 1 | 1 | 2017-03-31 00:00:00 | 2017-03-31 01:00:00 | 1 hour between 2017-03-31 00:00:00 and 2017-03-31 01:00:00 |
| Variable1 | 1 | 1 | 2017-03-31 02:00:00 | 2017-03-31 03:00:00 | 1 hour between 2017-03-31 02:00:00 and 2017-03-31 03:00:00 |
| Variable1 | 1 | 1 | 2017-03-31 23:00:00 | 2017-04-01 01:00:00 | 1 hour between 2017-03-31 23:00:00 and 2017-04-01 01:00:00 |
| Variable2 | 1 | 20 | 2017-03-31 04:00:00 | 2017-04-01 00:00:00 | 20 hours between 2017-03-31 04:00:00 and 2017-04-01 00:00:00 |
+-----------+-------+-------+---------------------+---------------------+--------------------------------------------------------------+
如果您经常需要这样做,可以考虑创建一个实际的表格数小时。否则,使用堆叠的cte与大多数其他选项一样快,并且随着生成的值的数量增加,它比递归cte快得多。
数字和日历表参考: