【问题标题】:SQL SUM hours between two dates & GROUP BY Column Name?两个日期和 GROUP BY 列名之间的 SQL SUM 小时数?
【发布时间】:2015-06-19 16:59:20
【问题描述】:

我需要像这样显示一个月内和前一个月内某项操作经过的总小时数:

 ___________________________________________
| Rank |  Action  |   Month    | Prev Month |
|------|----------|------------|------------|
| 1    | Action1  |      580.2 |      200.7 |
| 2    | Action8  |      412.5 |      550.2 |
| 3    | Action10 |      405.0 |       18.1 |
---------------------------------------------

我有一个格式如下的 SQL 表:

 _____________________________________________________
| Action  |     StartTime       |       EndTime       |
|---------|---------------------|---------------------|
| Action1 | 2015-02-03 06:01:53 | 2015-02-03 06:12:05 |
| Action1 | 2015-02-03 06:22:16 | 2015-02-03 06:25:33 |
| Action2 | 2015-02-03 06:36:07 | 2015-02-03 06:36:49 |
| Action1 | 2015-02-03 06:36:46 | 2015-02-03 06:48:10 |
| ..etc   | 20..-..-..   ...etc | 20..-..-..   ...etc |
-------------------------------------------------------

查询会是什么样子?

编辑:

A ツ 的回答让我朝着正确的方向前进,但是我使用 JOIN 解决了​​这个问题。请参阅下面的解决方案。

【问题讨论】:

  • 您能告诉我们您为实现这一目标所做的努力吗?
  • 你怎么知道是哪一个月?这会来自用户吗?
  • @wewestthemenace 月份将从日历日期小部件输入,并且仅显示生成的表中的前 10 个结果。

标签: sql sql-server datetime datediff


【解决方案1】:

我稍微改变了一些值,因为只有一天很无聊

INSERT INTO yourtable
    ([Action], [StartTime], [EndTime])
VALUES
    ('Action1', '2015-02-18 06:01:53', '2015-02-18 06:12:05'),
    ('Action1', '2015-02-18 06:22:16', '2015-02-18 06:25:33'),
    ('Action2', '2015-04-03 06:36:07', '2015-04-03 06:36:49'),
    ('Action1', '2015-03-19 06:36:46', '2015-03-19 06:48:10'),
    ('Action2', '2015-04-13 06:36:46', '2015-04-13 06:48:10'),
    ('Action2', '2015-04-14 06:36:46', '2015-04-14 06:48:10')
;

现在定义日期边界:

declare @dateEntry datetime = '2015-04-03';

declare @date1 date
      , @date2 date
      , @date3 date;

set @date1 = @dateEntry;               -- 2015-04-03
set @date2 = dateadd(month,-1,@date1); -- 2015-03-03 
set @date3 = dateadd(month,-1,@date2); -- 2015-02-03 

所选日期将包括在 2015-04-03 00:00 之前开始并在 2015-02-03 00:00 之后开始的所有操作

select date1 = @date1 
     , date2 = @date2
     , date3 = @date3
     , [Action] 
     , thisMonth = 
       sum(
       case when Starttime between @date2 and @date1 
            then datediff(second, starttime, endtime)/360.0
       end)
     , lastMonth =
       sum(
       case when Starttime between @date3 and @date2
            then datediff(second, starttime, endtime)/360.0
       end)
  from yourtable 
  where starttime between @date3 and @date1
  group by [Action]

http://sqlfiddle.com/#!6/35784/5

【讨论】:

  • 你很有帮助!我没有意识到您可以将 CASE 语句放在 SUM 字段中。唯一的问题是即使当前月份的值为 NULL,它也会收集所有结果(也收集上个月的数据)。将 WHERE 子句设置为 WHERE (StartTime BETWEEN @date2 AND @date1) 会从 lastMonth 字段中删除数据并添加 WHERE thisMonth IS NOT NULL 不起作用,因为 lastMonth 不是有效的列名
  • NULL 结果可以通过在GROUP BY 语句之后使用HAVING 来省略。但是,为了显示正确的结果,需要重复 SUMCASE 语句。
【解决方案2】:

我只是在对 SQL Server 进行了更多研究后重新审视了这个问题。

可以从查询创建临时表,然后在另一个查询中使用 - 嵌套查询如果您愿意。
这样,结果可以像通过任何其他普通表一样 JOIN 在一起,而没有讨厌的 CASE 语句。这对于显示第一个查询所需的其他数据也很有用,例如COUNT(DISTINCT ColumnName)

JOIN two SELECT statement results

SELECT TOP 10
    t1.Action, t1.[Time],
    COALESCE(t2.[Time],0) AS [Previous Period 'Time'],
    COALESCE( ( ((t1.[Time]*1.0) - (t2.[Time]*1.0)) / (t2.[Time]*1.0) ), -1 ) AS [Change]
FROM 
    (
        SELECT 
            Action, 
            SUM(DATEDIFF(SECOND, StartTime, EndTime)) AS [Time],
        FROM Actions
        WHERE StartTime BETWEEN @start AND @end
        GROUP BY Action
    ) t1
LEFT JOIN
    (
        SELECT 
            Action, 
            SUM(DATEDIFF(SECOND, StartTime, EndTime)) AS [Time]
        FROM Actions
        WHERE StartTime BETWEEN @prev AND @start
        GROUP BY Action
    ) t2
ON
    t1.Action = t2.Action
ORDER BY t1.[Time] DESC

希望这些信息对某人有所帮助。

【讨论】:

    【解决方案3】:

    您可能应该检查预处理数据的使用分组,如下所示:

    select Action, SUM(Hours)
      from (select Action, DATEDIFF('hh',StartTime, EndTime) as Hours
      FROM Actions)
    group by Action
    

    【讨论】:

      【解决方案4】:

      我的假设是你开始 - 结束时间跨度很短,你不必担心跨越 2 个月的日期,所以你可能需要这样的东西:

      select 
        dense_rank() over (order by Month desc) as Rank,
        action,
        Month,
        PrevMonth
      from
      (
        select
          action,
          sum(case when StartTime >= @curMonth then hours else 0 end) as Month,
          sum(case when StartTime >= @prevMonth and StartTime < @curMonth then hours else 0 end) as PrevMonth
        from
        (
          select 
            action, 
            StartTime,
            datediff(second, StartTime, EndTime) / 3600.0 as hours
          from
            yourtable
        ) T1
          group by
             action
      ) T2
      

      这会计算持续时间为秒,然后将其除以 3600 以获得小时数。排名仅基于当前月份。这需要您有 2 个变量 @curMonth 和 @prevMonth 具有限制的日期,并且没有未来的数据。

      用于测试的 SQL Fiddle:http://sqlfiddle.com/#!6/d64b7d/1

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2021-10-07
        • 2022-01-24
        • 1970-01-01
        • 2020-01-19
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多