【问题标题】:TSQL Query returns values for each hour for the past 24 hoursTSQL 查询返回过去 24 小时内每小时的值
【发布时间】:2012-09-12 12:09:13
【问题描述】:

我有一个不知道如何开始的查询。我希望有人能帮我解决这个问题。我将从解释表格开始

我有一个包含四列的设备表:Device_Id、Device_Status、Begin_dt、End_dt 有 6 种不同的状态,其中 3(为简单起见,我们说状态 1、4 和 5)表示设备“在线”

这个表的一个例子可以是

Id | Status| Begin                   |  End
001|     1 | 2012-09-01 00:00:00.000 | 2012-09-01 01:00:00.000
001|     2 | 2012-09-01 01:00:00.000 | 2012-09-01 01:35:00.000
001|     1 | 2012-09-01 01:35:00.000 | 2012-09-01 02:05:00.000
003|     1 | 2012-09-01 05:00:00.000 | 2012-09-01 07:02:00.000
004|     1 | 2012-09-01 01:00:00.000 | 2012-09-01 01:35:00.000
003|     2 | 2012-09-01 07:02:00.000 | NULL

我的查询需要返回 TIME 的总和,所有设备在 24 小时内每个小时都处于“在线”状态。

所以我的回报应该是这样的

Hour| Online_Time
0   | 5:30:12.11
1   | 3:30:12.11
2   | 4:30:12.11
3   | 5:30:12.11
4   | 6:30:12.11
5   | 4:00:00.00
6   | 1:30:12.11
7   | 3:30:12.11
8   | 4:30:12.11
etc |

因此,一天中的每个小时我都可以有超过 1 小时的在线时间(显然),因为例如,如果我有 5 台设备在整个小时内都在线,那么我将有 5 小时的在线时间。

这有点复杂,我希望我能很好地解释它,非常感谢任何可以提供帮助或提供建议的人。

-J


with const as (
    select dateadd(hour, 1, cast(cast(getdate() -1 as date) as datetime)) as midnnight
    ),
allhours as (
    select 0 as hour, midnight as timestart, dateadd(hour, 1, timestart) as timeend from const union all
    select 1 as hour, dateadd(hour, 1, midnight), dateadd(hour, 2, midnight) from const union all
    select 2 as hour, dateadd(hour, 2, midnight), dateadd(hour, 3, midnight) from const union all
    select 3 as hour, dateadd(hour, 3, midnight), dateadd(hour, 4, midnight) from const union all
    select 4 as hour, dateadd(hour, 4, midnight), dateadd(hour, 5, midnight) from const union all
    select 5 as hour, dateadd(hour, 5, midnight), dateadd(hour, 6, midnight) from const union all
    select 6 as hour, dateadd(hour, 6, midnight), dateadd(hour, 7, midnight) from const union all
    select 7 as hour, dateadd(hour, 7, midnight), dateadd(hour, 8, midnight) from const union all
    select 8 as hour, dateadd(hour, 8, midnight), dateadd(hour, 9, midnight) from const union all
    select 9 as hour, dateadd(hour, 9, midnight), dateadd(hour, 10, midnight) from const union all
    select 10 as hour, dateadd(hour, 10, midnight), dateadd(hour, 11, midnight) from const union all
    select 11 as hour, dateadd(hour, 11, midnight), dateadd(hour, 12, midnight) from const union all
    select 12 as hour, dateadd(hour, 12, midnight), dateadd(hour, 13, midnight) from const union all
    select 13 as hour, dateadd(hour, 13, midnight), dateadd(hour, 14, midnight) from const union all
    select 14 as hour, dateadd(hour, 14, midnight), dateadd(hour, 15, midnight) from const union all
    select 15 as hour, dateadd(hour, 15, midnight), dateadd(hour, 16, midnight) from const union all
    select 16 as hour, dateadd(hour, 16, midnight), dateadd(hour, 17, midnight) from const union all
    select 17 as hour, dateadd(hour, 17, midnight), dateadd(hour, 18, midnight) from const union all
    select 18 as hour, dateadd(hour, 18, midnight), dateadd(hour, 19, midnight) from const union all
    select 19 as hour, dateadd(hour, 19, midnight), dateadd(hour, 20, midnight) from const union all
    select 20 as hour, dateadd(hour, 20, midnight), dateadd(hour, 21, midnight) from const union all
    select 21 as hour, dateadd(hour, 21, midnight), dateadd(hour, 22, midnight) from const union all
    select 22 as hour, dateadd(hour, 22, midnight), dateadd(hour, 23, midnight) from const union all
    select 23 as hour, dateadd(hour, 23, midnight), dateadd(hour, 24, midnight) from const union all
   ) 
select ah.hour,
   sum(datediff(ms, (case when ah.timestart >= dt.Begin_Dt then timestart else dt.Begin_Dt end),
                    (case when ah.timeend <= dt.End_Dt then ah.timeend else dt.End_Dt end))) as totalms,
   cast(dateadd(ms, sum(datediff(ms, (case when ah.timestart >= dt.Begin_Dt then timestart else dt.Begin_Dt end),
                                 (case when ah.timeend <= dt.End_Dt then ah.timeend else dt.End_Dt end))),0) as time
                                 ) as totalTime
from allhours as ah left outer join
     dataTable as dt
     on ah.timestart< coalesce(dt.End_dt, getdate()) and
        ah.timeend >= dt.Begin_Dt
group by ah.hour
order by ah.hour

这就是我现在所拥有的,')' 上出现错误

select 23 as hour, dateadd(hour, 23, midnight), dateadd(hour, 24, midnight) from const union all
   )  <----- Incorrect syntax near ')'. Expecting SELECT, or '('.
select ah.hour,

【问题讨论】:

    标签: tsql ssms


    【解决方案1】:

    您的问题似乎是时间跨度需要以小时为单位。因此,您需要从一天中的所有时间开始。然后计算重叠,总结差异(以毫秒为单位)并将所有内容转换回输出时间。

    with const as (
            select dateadd(hour, 1, cast(cast(getdate() -1 as date) as datetime)) as midnight            
        ),
        allhours as (
            select 0 as hour, midnight as timestart, dateadd(hour, 1, midnight) as timeend from const union all
            select 1 as hour, dateadd(hour, 1, midnight), dateadd(hour, 2, midnight) from const union all
            select 2 as hour, dateadd(hour, 2, midnight), dateadd(hour, 3, midnight)  from const union all
            . . .
            select 23 as hour, dateadd(hour, 23, midnight), dateadd(hour, 24, midnight) from const
        )
    select ah.hour,
           sum(datediff(ms, (case when ah.timestart >= dt.begin then timestart else dt.begin end),
                            (case when ah.timeend <= dt.end then ah.timeend else dt.end end)
                       ) 
               ) as totalms,
           cast(dateadd(ms, sum(datediff(ms, (case when ah.timestart >= dt.begin then timestart else dt.begin end),
                                         (case when ah.timeend <= dt.end then ah.timeend else dt.end end)
                                        )
                               ),
                         0) as time
               ) as totalTime
    from allhours ah left outer join
         DeviceTable dt
         on ah.timestart< coalesce(dt.end, getdate()) and
            ah.timeend >= dt.begin
    group by ah.hour
    order by ah.hour
    

    此外,为了使这项工作,您需要将“开始”和“结束”用双引号或方括号括起来。这些是 T-SQL 中的保留字。你需要替换“......”从 3 到 22 小时有额外的线路。

    【讨论】:

    • 感谢戈登的回复!但是,我在语法上遇到了一些麻烦。我的大部分经验是在 vb.net 中,我有基本的 sql/tsql 知识。实际上,我今天刚刚被介绍到 CTE 的想法。我正在阅读该主题,似乎我需要在我的 CTE 中指定列名。所以我有点困惑
    • with const as (select dateadd(hour, 1, cast(cast(getdate() -1 as date) as datetime)) as midnn​​ight,),....不应该是什么like.. with const (COLUMN NAME) as ( select dateadd(hour, 1, cast(cast(getdate() -1 as date) as datetime)) as midnn​​ight, ),任何详细说明都会很有帮助
    • @BrandonJ 。 . .我修复了语法问题。您需要更改 begin 和 end 的名称,或将它们括在方括号中,以使查询真正起作用。
    • 非常感谢 Gordon,是的,我确实对开始和结束进行了更改,但我仍然遇到一个语法问题 [对不起,我是新手 :( ]
    • ) 选择 ah.hour, ------- 语法错误在右括号中,它表示 ')' 附近的语法错误,期望 SELECT 或 '('。-令人困惑,因为下一行是一个选择语句。有什么想法吗?
    【解决方案2】:

    这样的事情可能会让你开始。

    select  SUM(datediff(second, Begin_dt, End_dt)) as seconds_online
            ,DATEPART(hour, Begin_dt) as [hour]
    from table
    where device_status in (1,4,5)
    group by DATEPART(hour, Begin_dt)
    

    要格式化结果,您可能需要关注这个问题:

    SQL - Seconds to Day, Hour, Minute, Second

    【讨论】:

    • 谢谢约翰,我会从那开始。我会为你的帖子投票,但我只是为这个帖子注册了一个帐户,还没有所需的声誉:/
    猜你喜欢
    • 2018-06-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-03-15
    • 2018-06-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多