繁体   English   中英

SQL查询计算按天分组的两个日期之间的小时数

[英]SQL Query to calculate the hours between two dates grouped by days

我需要为以下场景编写 SQL 查询。

我的开始日期为 2020-01-10 13:00:00.347,结束日期为 2020-01-12 02:00:00.347,所以我需要将数据分组为

Day              Hours
----             -----
10-01-2020       11
11-01-2020       24
12-01-2020       2.30 

这意味着第一个日期为 11 小时,第二天为 24 小时,第三天为 2.3 小时。

获取上述格式数据的最高效 SQL 查询是什么? 提前致谢。

您可以使用递归 CTE 将日期分成多个范围:

with recursive cte as (
       select start_date as day_start,
              (case when date(start_date) = date(end_date) then end_date else date(start_date) + interval 1 day end) as day_end,
              end_date
       from (select cast('2020-01-10 13:00:00.347' as datetime) as start_date,
                    cast('2020-01-12 02:00:00.347' as datetime) as end_date
            ) t
       union all
       select day_end,
              (case when date(day_end) = date(end_date) then end_date else date(day_end) + interval 1 day end) as day_end,
              end_date
       from cte
       where day_end <> end_date
     )
select day_start, day_end,
       timestampdiff(second, day_start, day_end) / (60 * 60)
from cte;

是一个 db<>fiddle。

编辑:

在 SQL Server 中,这看起来像:

with cte as (
       select start_date as day_start,
              (case when cast(start_date as date) = cast(end_date as date) then end_date else dateadd(day, 1, cast(start_date as date)) end) as day_end,
              end_date
       from (select cast('2020-01-10 13:00:00.347' as datetime) as start_date,
                    cast('2020-01-12 02:00:00.347' as datetime) as end_date
            ) t
       union all
       select day_end,
              (case when cast(day_end as date) = cast(end_date as date) then end_date else dateadd(day, 1, day_end) end) as day_end,
              end_date
       from cte
       where day_end <> end_date
     )
select day_start, day_end,
       datediff(second, day_start, day_end) / (60.0 * 60)
from cte;

是这个 db<>fiddle。

由于 OP 要求最有效的方法,并且众所周知 rCTE 的性能很差,因此更有效的方法是使用 Tally。

对于初学者来说,这并不容易阅读,但是,确实得到了您想要的结果(除了2020-01-12的值为2.0而不是2.3 ,因为您的数学显然是错误的) :

CREATE TABLE dbo.YourTable (StartDate datetime,
                            EndDate datetime);

INSERT INTO dbo.YourTable (StartDate,
                           EndDate)
VALUES('2020-01-10T13:00:00.347','2020-01-12T02:00:00.347'),
      ('2020-01-14T17:24:41.243','2020-01-19T09:17:12.997');
GO

WITH N AS(
    SELECT N
    FROM (VALUES(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL))N(N)),
Tally AS(
    SELECT TOP(SELECT MAX(DATEDIFF(DAY, StartDate, EndDate)+1) FROM dbo.YourTable)
           ROW_NUMBER() OVER (ORDER BY (SELECT NULL)) -1 AS I
    FROM N N1, N N2, N N3), --1000 days enough?
Dates AS(
    SELECT DATEADD(DAY, T.I,CONVERT(date,YT.StartDate)) AS [Date],
           CASE WHEN T.I = 0 THEN YT.StartDate ELSE DATEADD(DAY, T.I,CONVERT(date,YT.StartDate)) END AS StartingDateTime,
           CASE WHEN LEAD(T.I) OVER (PARTITION BY YT.StartDate ORDER BY T.I) IS NULL THEN YT.EndDate ELSE DATEADD(DAY, T.I+1,CONVERT(date,YT.StartDate)) END AS EndingDateTime
    FROM Tally T
         JOIN dbo.YourTable YT ON T.I <= DATEDIFF(DAY, YT.StartDate, YT.EndDate))
SELECT D.[Date],
       (DATEDIFF(SECOND,D.StartingDateTime,D.EndingDateTime) * 1.0) / 60 / 60 AS [Hours]
FROM Dates D;

GO

DROP TABLE dbo.YourTable;

数据库<>小提琴

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM