【问题标题】:SQL Query to find difference in hours between first and last records of each day for a month, and sum each difference to find the totalSQL查询查找一个月中每天的第一条记录和最后一条记录之间的小时数差异,并将每个差异求和以找到总数
【发布时间】:2015-12-04 13:08:49
【问题描述】:

这不是用一句话描述的最简单的查询,这就是为什么标题可能不是最好的原因。

基本上我有登录日志。此日志如下所示:

ContactId, LocationId, TimeStamp

这些代表在给定时间在某个位置看到的联系人(注册人)。

我想要做的是选择一个日期时间窗口,并且对于该窗口中的每一天,我想进行第一次登录和最后一次登录并计算小时差。然后,这种小时数差异应计入总时间,从而估算出联系人在当月在该地点花费的总时间。

显然应该忽略没有看到联系人的天数,也不应该使用只看到一次联系人的天数,因为无法计算差异。

我知道如何以小时为单位找出两个日期时间之间的差异:

select DATEDIFF(HOUR, datetime1, datetime2) as hoursestimate

但我不确定如何:

  1. 将 datetime1 和 datetime2 设为一天的第一条和最后一条记录。
  2. 循环遍历数据以增加天数,以查找该月的累计总小时数 (TotalHours)。

一旦我根据第一次和最后一次看到的差异获得了一段时间内的累计总小时数,我将与我的联系人表执行连接,以通过此 TotalHours 列获取他们的名字和姓氏以及顺序,因此希望是最终表我想从查询中返回会是这样的:

Id    FirstName     LastName     TotalHours
35     Bob          Bobberson    65
40     Jim          Jimmerson    63
2      Harry        Harrison     54

然而,我有点迷失了第 1 步和第 2 步。有什么想法吗?

【问题讨论】:

    标签: sql sql-server


    【解决方案1】:

    我认为你想要两个聚合:

    select contactid, sum(hoursestimate) as total
    from (select contactid, cast(TimeStamp as date) as dte,
                 DATEDIFF(HOUR, min(TimeStamp), max(TimeStamp)) as hoursestimate
          from t
          where TimeStamp >= @start and TimeStamp < @end
          group by contactid, cast(TimeStamp as date)
         ) t
    group by contactid;
    

    【讨论】:

    • 感谢这完美的作品!我在 SQL 方面不是最好的,但我遵循你所做的,我想我学到了一些东西!也为快速响应干杯。
    • 下面的答案使用了一个有声明来忽略我们在一天中只见过一次的联系人。当联系人被查看一次时,此查询中会发生什么?我假设最小值和最大值是相同的,所以总小时数没有贡献?
    • 您当然可以过滤掉 0 个贡献小时数。只需将 where hoursestimate 0 添加到外部查询即可。
    【解决方案2】:

    这里有几种不同的技术可以为您提供帮助。

    CAST 将允许您将日期时间戳的日期和时间部分彼此剥离。这对于将同一天但不同时间的多条记录分组在一起非常方便。

    HAVING 可用于过滤掉一天内只有记录的联系人。这是通过计算贡献记录的数量并删除低于阈值的记录来实现的。

    这个例子结合了这些技术:

    Exmaple

    WITH SampleDate AS
        (
            /* Lets make some records to experiment with.
             */
            SELECT
                r.*
            FROM
                (
                    VALUES
                        (1, 1, '2015-01-01 09:00:00.000'),
                        (1, 1, '2015-01-01 12:00:00.000'),
                        (1, 1, '2015-01-01 17:00:00.000'),
                        (2, 1, '2015-01-01 09:00:00.000')
                ) AS r(ContactId, LocationId, [TimeStamp])
        )
    SELECT
        ContactId, 
        LocationId,
        CAST([TimeStamp] AS DATE)                AS [Day],    
        MIN(CAST([TimeStamp] AS TIME))            AS FirstSeenTime,
        MAX(CAST([TimeStamp] AS TIME))            AS LastSeenTime,    
        DATEDIFF(
            HOUR,
            MIN(CAST([TimeStamp] AS TIME)),
            MAX(CAST([TimeStamp] AS TIME))
        )                                        AS HoursEstimate
    FROM
        SampleDate
    GROUP BY
        ContactId, 
        LocationId,
        CAST([TimeStamp] AS DATE)        -- Removing the time allows us to create 1 record per day.
    HAVING
        COUNT(*) > 1                    -- Make sure we've seen the contact at least twice.
    ;
    

    【讨论】:

    • 感谢您的回复和解释。答案的主要区别是Having语句....当我们在给定的一天只看到一次联系人时,您能解释一下另一个答案中发生的事情吗?我担心缺少Having语句可能不准确,但仅通过查看我的数据输出很难判断。 @ReleaseObject
    • 我假设最小值和最大值是相同的,所以总小时数没有贡献?
    • 是的,你是对的。最小值和最大值相同,估计时间为 0 小时。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-06-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-04-09
    相关资源
    最近更新 更多