对于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快得多。
数量和日历表参考:
按小时这是永远? – SqlZim