sql-server - T-SQL - 两个日期时间之间每小时的分钟数

标签 sql-server tsql date datetime

我需要以下数据:

 | tid | startdate        | enddate                |
 | 1   | 2016-12-26 12:30 | 2016-12-26 15:30       |
 | 2   | 2016-12-26 13:15 | 2016-12-26 15:15       |

我想创建一个结果,其中包含小时数,然后是日期时间在该小时内的分钟数。

示例结果:

 | tid | hour | minutes_in |
 | 1   | 12   | 30         |
 | 1   | 13   | 60         |
 | 1   | 14   | 60         |
 | 1   | 15   | 30         |
 | 2   | 13   | 45         |
 | 2   | 14   | 60         |
 | 2   | 15   | 15         |

有什么建议吗?

最佳答案

首先,您需要一个数字表来获取从 0 到 23 的小时数,可以使用表值构造函数轻松地即时创建它:

SELECT N
FROM (VALUES 
        (0),(1),(2),(3),(4),(5),(6),(7),(8),(9),(10),(11),(12),
        (13),(14),(15),(16),(17),(18),(19),(20),(21),(22),(23)
    ) n (N);

然后您可以将其连接到您的原始数据以将行拆分为所需的数量。然后你只需要一个 case 表达式来应用正确的逻辑来计算分钟:

WITH Numbers (Number) AS
(   SELECT N
    FROM (VALUES 
            (0),(1),(2),(3),(4),(5),(6),(7),(8),(9),(10),(11),(12),
            (13),(14),(15),(16),(17),(18),(19),(20),(21),(22),(23)
        ) n (N)
), SampleData (tid, StartDate, EndDate) AS
(   SELECT  tid, CONVERT(DATETIME2, StartDate), CONVERT(DATETIME2, EndDate)
    FROM (VALUES 
            (1, '2016-12-26 12:30', '2016-12-26 15:30'),
            (2, '2016-12-26 13:15', '2016-12-26 15:15')
        ) d (tid, StartDate, EndDate)
)
SELECT  d.tid,
        [Hour] = n.Number,
        Minutes_in = CASE  
                        -- SPECIAL CASE: START HOUR = END HOUR
                        WHEN DATEPART(HOUR, d.StartDate) = DATEPART(HOUR, d.EndDate) 
                            THEN DATEDIFF(MINUTE, d.StartDate, d.EndDate)

                        -- FULL HOURS IN BETWEEN START AND END
                        WHEN n.Number > DATEPART(HOUR, d.StartDate) 
                            AND n.Number < DATEPART(HOUR, d.EndDate) THEN 60

                        -- START HOUR
                        WHEN n.Number = DATEPART(HOUR, d.StartDate) 
                            THEN 60 - DATEPART(MINUTE, d.StartDate)

                        -- END HOUR
                        WHEN n.Number = DATEPART(HOUR, d.EndDate) 
                            THEN DATEPART(MINUTE, d.EndDate)
                    END
FROM    SampleData d
        INNER JOIN Numbers n 
            ON n.Number >= DATEPART(HOUR, d.StartDate)
            AND n.Number <= DATEPART(HOUR, d.EndDate);

附录

如果您需要跨越几天,那么您可以稍微改变逻辑,生成一组更大的数字以涵盖更多的小时差异,然后不要在一天中的小时加入,而是在小时差异上加入数字开始日期时间到结束日期时间:

SELECT  *
FROM    SampleData d
        INNER JOIN Numbers n 
            ON n.Number <= DATEDIFF(HOUR, d.StartDate, d.EndDate)

这意味着范围跨越了几天,那么就没有问题,小时数只是不断增加。例如

WITH Numbers (Number) AS
(   SELECT ROW_NUMBER() OVER(ORDER BY N1.N) - 1
    FROM (VALUES (1),(1),(1),(1),(1),(1),(1),(1),(1),(1)) N1(N)
    CROSS JOIN (VALUES (1),(1),(1),(1),(1),(1),(1),(1),(1),(1)) N2 (N)
    CROSS JOIN (VALUES (1),(1),(1),(1),(1),(1),(1),(1),(1),(1)) N3 (N)
    CROSS JOIN (VALUES (1),(1),(1),(1),(1),(1),(1),(1),(1),(1)) N4 (N)
), SampleData (tid, StartDate, EndDate) AS
(   SELECT  tid, CONVERT(DATETIME2, StartDate), CONVERT(DATETIME2, EndDate)
    FROM (VALUES 
            (1, '2016-12-26 12:30', '2016-12-26 15:30'),
            (2, '2016-12-26 13:15', '2016-12-26 15:15'),
            (3, '2016-12-26 13:15', '2016-12-27 15:15')
        ) d (tid, StartDate, EndDate)
)
SELECT  d.tid,
        [Date] = CONVERT(DATE, d.StartDate),
        [Hour] = CONVERT(TIME(0), DATEADD(HOUR, DATEPART(HOUR, d.StartDate) + n.Number, 0)),
        Minutes_in = CASE  
                        -- SPECIAL CASE: START HOUR = END HOUR
                        WHEN DATEPART(HOUR, d.StartDate) = DATEPART(HOUR, d.EndDate)
                            AND DATEDIFF(DAY, d.StartDate, d.EndDate) = 0
                            THEN DATEDIFF(MINUTE, d.StartDate, d.EndDate)

                        -- START HOUR
                        WHEN n.Number = 0
                            THEN 60 - DATEPART(MINUTE, d.StartDate)

                        -- END HOUR
                        WHEN n.Number = DATEDIFF(HOUR, d.StartDate, d.EndDate) 
                            THEN DATEPART(MINUTE, d.EndDate)

                        -- FULL HOURS IN BETWEEN START AND END
                        ELSE 60

                    END
FROM    SampleData d
        INNER JOIN Numbers n 
            ON n.Number <= DATEDIFF(HOUR, d.StartDate, d.EndDate)
ORDER BY d.tid, n.Number;

关于sql-server - T-SQL - 两个日期时间之间每小时的分钟数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/40973342/

相关文章:

sql - 什么保证 SQL 规范为 UPDATE 提供读取和写入某些列的内容

c# - 需求变更 : Use database table instead of enums. 如何处理使用枚举值的现有记录?

mysql - 从年份和月份变量中获取月份的第一天和最后一天

ruby-on-rails - 使用rails_admin为日期字段添加默认值

php - 如何确定日期是否在 PHP 中的两个日期之间?

SQL Server 删除脚本顺序

sql - 帮助进行 SQL 查询

sql - 在 T-SQL 查询中,仅需要获取根元素的属性名称-值对

asp.net - 如何在 Sql Server 中插入新行后立即获取新的身份 ID?

java - 我如何从 sqlserver 检索错误消息给我的 java 程序员