按小时计算的总分钟数

时间:2015-05-01 02:09:34

标签: sql-server sql-server-2005

我在数据表中有两个字段 - " startTime"和" endTime。"这两个字段表示用户在特定任务上花费的持续时间。这些是varchar字段。所以,我们假设我们的开始时间为" 21:05:00"结束时间为" 22:09:00。"我需要代码来计算在21小时和22小时内(即9分钟)花费的总分钟数。所以,不仅仅是一个简单的微小差异,而是按小时分解。

最好的方法是什么?

到目前为止,我已经创建了一个表,它将在24小时内返回所有可能的小时数。这是一个样本:

Hour    startTime                endTime
0       2015-01-01 00:00:00.000  2015-01-01 01:00:00.000
1       2015-01-01 01:00:00.000  2015-01-01 02:00:00.000
2       2015-01-01 02:00:00.000  2015-01-01 03:00:00.000

我已将startTime字段从varchar转换为dateteime,并将其命名为sessionHour:

Convert(datetime, startTime) As sessionHour

此外,我还可以通过以下方式获取startTime的小时:

DateAdd(Minute, 60 * (DateDiff(Minute, 0, startTime) / 60), 0)  As hourOf

除此之外,我对如何解析每小时的分钟感到迷茫。

2 个答案:

答案 0 :(得分:2)

你非常接近。您只需要将数字表与数据相结合。我会使用CROSS APPLY。这是[{3}}最终解决方案。

示例数据

DECLARE @Durations TABLE (ID int IDENTITY(1,1), StartTime datetime, EndTime datetime);

INSERT INTO @Durations VALUES
('2015-01-01 21:05:00', '2015-01-01 22:09:00'),
('2015-01-01 01:05:00', '2015-01-01 01:20:00'),
('2015-01-01 11:05:00', '2015-01-01 13:09:00'),
('2015-01-01 15:05:00', '2015-01-01 17:50:00'),
('2015-01-01 16:30:00', '2015-01-01 17:20:00');

我从一开始就使用datetime类型,因为您已将varchar值转换为正确的datetime

我会使用一张数字表。它应该具有与数据中最长持续时间(以小时为单位)相同的行数。它可能超过24个。通常,在数据库中为其他报告提供此类表是有用的。

DECLARE @Numbers TABLE (Number int);
INSERT INTO @Numbers VALUES (0),(1),(2),(3),(4),(5),(6),(7),(8),(9),(10);
-- Number of rows in this table should be more than the longest duration in hours

我需要一些参考时间点来移除datetime的分钟部分。它可以是任何日期时间,只要它没有分钟和秒。

DECLARE @VarStart datetime;
SET @VarStart = '2000-01-01';

主要步骤 - 展开数据

SELECT *
FROM
    @Durations AS D
    CROSS APPLY
    (
        SELECT N.Number
        FROM @Numbers AS N
        WHERE N.Number <= DATEDIFF(hour, StartTime, EndTime)
    ) AS CA_Number
ORDER BY ID;

ID   StartTime              EndTime                Number
1    2015-01-01 21:05:00    2015-01-01 22:09:00    0
1    2015-01-01 21:05:00    2015-01-01 22:09:00    1
2    2015-01-01 01:05:00    2015-01-01 01:20:00    0
3    2015-01-01 11:05:00    2015-01-01 13:09:00    0
3    2015-01-01 11:05:00    2015-01-01 13:09:00    1
3    2015-01-01 11:05:00    2015-01-01 13:09:00    2
4    2015-01-01 15:05:00    2015-01-01 17:50:00    0
4    2015-01-01 15:05:00    2015-01-01 17:50:00    1
4    2015-01-01 15:05:00    2015-01-01 17:50:00    2
5    2015-01-01 16:30:00    2015-01-01 17:20:00    0
5    2015-01-01 16:30:00    2015-01-01 17:20:00    1

您可以看到我们为每个原始行创建了几行,具体取决于原始行的持续时间。其余的是简单的算术。

每小时分钟

SELECT *
    ,DATEDIFF(minute, MaxStart, MinEnd) AS MinutesPerHour
FROM
    @Durations AS D
    CROSS APPLY
    (
        SELECT N.Number
        FROM @Numbers AS N
        WHERE N.Number <= DATEDIFF(hour, StartTime, EndTime)
    ) AS CA_Number
    CROSS APPLY
    (
        SELECT
            DATEADD(hour, CA_Number.Number, StartTime) AS HourStart
            ,DATEADD(hour, CA_Number.Number+1, StartTime) AS HourEnd
    ) AS CA_HourEnd
    CROSS APPLY
    (
        -- Truncate to 1 hour.
        SELECT
            DATEADD(hour, DATEDIFF(hour, @VarStart, HourStart), @VarStart) AS HourStartFinal
            ,DATEADD(hour, DATEDIFF(hour, @VarStart, HourEnd), @VarStart) AS HourEndFinal
    ) AS CA_HourEndFinal
    -- Intersect intervals [StartTime, EndTime] with [HourStartFinal, HourEndFinal]
    CROSS APPLY
    (
        SELECT
            CASE WHEN StartTime > HourStartFinal THEN StartTime ELSE HourStartFinal END AS MaxStart
            ,CASE WHEN EndTime < HourEndFinal THEN EndTime ELSE HourEndFinal END AS MinEnd
    ) AS CA_Intersect
ORDER BY ID;

CA_HourEndCA_HourEndFinal中,我使用Number计算小时边界。然后相交两个间隔并计算每个交叉点的分钟数。这是结果集:

ID   StartTime              EndTime                Number    HourStart              HourEnd                HourStartFinal         HourEndFinal           MaxStart               MinEnd                 MinutesPerHour
1    2015-01-01 21:05:00    2015-01-01 22:09:00    0         2015-01-01 21:05:00    2015-01-01 22:05:00    2015-01-01 21:00:00    2015-01-01 22:00:00    2015-01-01 21:05:00    2015-01-01 22:00:00    55
1    2015-01-01 21:05:00    2015-01-01 22:09:00    1         2015-01-01 22:05:00    2015-01-01 23:05:00    2015-01-01 22:00:00    2015-01-01 23:00:00    2015-01-01 22:00:00    2015-01-01 22:09:00    9
2    2015-01-01 01:05:00    2015-01-01 01:20:00    0         2015-01-01 01:05:00    2015-01-01 02:05:00    2015-01-01 01:00:00    2015-01-01 02:00:00    2015-01-01 01:05:00    2015-01-01 01:20:00    15
3    2015-01-01 11:05:00    2015-01-01 13:09:00    0         2015-01-01 11:05:00    2015-01-01 12:05:00    2015-01-01 11:00:00    2015-01-01 12:00:00    2015-01-01 11:05:00    2015-01-01 12:00:00    55
3    2015-01-01 11:05:00    2015-01-01 13:09:00    1         2015-01-01 12:05:00    2015-01-01 13:05:00    2015-01-01 12:00:00    2015-01-01 13:00:00    2015-01-01 12:00:00    2015-01-01 13:00:00    60
3    2015-01-01 11:05:00    2015-01-01 13:09:00    2         2015-01-01 13:05:00    2015-01-01 14:05:00    2015-01-01 13:00:00    2015-01-01 14:00:00    2015-01-01 13:00:00    2015-01-01 13:09:00    9
4    2015-01-01 15:05:00    2015-01-01 17:50:00    0         2015-01-01 15:05:00    2015-01-01 16:05:00    2015-01-01 15:00:00    2015-01-01 16:00:00    2015-01-01 15:05:00    2015-01-01 16:00:00    55
4    2015-01-01 15:05:00    2015-01-01 17:50:00    1         2015-01-01 16:05:00    2015-01-01 17:05:00    2015-01-01 16:00:00    2015-01-01 17:00:00    2015-01-01 16:00:00    2015-01-01 17:00:00    60
4    2015-01-01 15:05:00    2015-01-01 17:50:00    2         2015-01-01 17:05:00    2015-01-01 18:05:00    2015-01-01 17:00:00    2015-01-01 18:00:00    2015-01-01 17:00:00    2015-01-01 17:50:00    50
5    2015-01-01 16:30:00    2015-01-01 17:20:00    0         2015-01-01 16:30:00    2015-01-01 17:30:00    2015-01-01 16:00:00    2015-01-01 17:00:00    2015-01-01 16:30:00    2015-01-01 17:00:00    30
5    2015-01-01 16:30:00    2015-01-01 17:20:00    1         2015-01-01 17:30:00    2015-01-01 18:30:00    2015-01-01 17:00:00    2015-01-01 18:00:00    2015-01-01 17:00:00    2015-01-01 17:20:00    20

最终查询

最后,我将分钟数分组一小时:

SELECT
    HourStartFinal
    ,SUM(DATEDIFF(minute, MaxStart, MinEnd)) AS SumMinutesPerHour
FROM
    @Durations AS D
    CROSS APPLY
    (
        SELECT N.Number
        FROM @Numbers AS N
        WHERE N.Number <= DATEDIFF(hour, StartTime, EndTime)
    ) AS CA_Number
    CROSS APPLY
    (
        SELECT
            DATEADD(hour, CA_Number.Number, StartTime) AS HourStart
            ,DATEADD(hour, CA_Number.Number+1, StartTime) AS HourEnd
    ) AS CA_HourEnd
    CROSS APPLY
    (
        -- Truncate to 1 hour.
        SELECT
            DATEADD(hour, DATEDIFF(hour, @VarStart, HourStart), @VarStart) AS HourStartFinal
            ,DATEADD(hour, DATEDIFF(hour, @VarStart, HourEnd), @VarStart) AS HourEndFinal
    ) AS CA_HourEndFinal
    -- Intersect intervals [StartTime, EndTime] with [HourStartFinal, HourEndFinal]
    CROSS APPLY
    (
        SELECT
            CASE WHEN StartTime > HourStartFinal THEN StartTime ELSE HourStartFinal END AS MaxStart
            ,CASE WHEN EndTime < HourEndFinal THEN EndTime ELSE HourEndFinal END AS MinEnd
    ) AS CA_Intersect
GROUP BY HourStartFinal
ORDER BY HourStartFinal;

最终结果集

HourStartFinal             SumMinutesPerHour
2015-01-01 01:00:00.000    15
2015-01-01 11:00:00.000    55
2015-01-01 12:00:00.000    60
2015-01-01 13:00:00.000    9
2015-01-01 15:00:00.000    55
2015-01-01 16:00:00.000    90
2015-01-01 17:00:00.000    70
2015-01-01 21:00:00.000    55
2015-01-01 22:00:00.000    9

SQLFiddle

答案 1 :(得分:0)

您可能希望查看datepart()功能,它可以帮助您更干净地操纵日期。例如:

select @endOfHour = dateadd(hour,
    1,
    datetimefromparts(
        datepart(year, @startTime),
        datepart(month, @startTime),
        datepart(day, @startTime),
        datepart(hour, @startTime),
        0,
        0,
        0));


select h.theHour, @startTime, @endOfHour, datediff(minute, @startTime, @endOfHour)
from ListOfHours as h
where datepart(hour, @startTime) = h.Hour;