Sql server 选择在一天中特定小时发生的持续时间部分

Sql server 选择在一天中特定小时发生的持续时间部分,sql-server,sql-server-2008,tsql,sql-server-2008-r2,Sql Server,Sql Server 2008,Tsql,Sql Server 2008 R2,在SQL Server中,我有一个包含starttime和endtime的进程表,从中可以使用DATEDIFF计算持续时间 Name StartTime EndTime ------------------------------------------------ process1 2016-10-10 11:10 2016-10-10 11:20 process2 2016-10-10 11:40 2016-10-10 12:30

在SQL Server中,我有一个包含starttime和endtime的进程表,从中可以使用DATEDIFF计算持续时间

Name        StartTime           EndTime
------------------------------------------------
process1    2016-10-10 11:10    2016-10-10 11:20
process2    2016-10-10 11:40    2016-10-10 12:30
如何选择在第11天和第12天的特定小时(以秒为单位)内发生的流程持续时间的时间跨度

所以process1将是11小时内的10分钟。
进程2在第11小时为20分钟,在第12小时为30分钟。

我认为这是成功的,但它非常难看。也许有人能做得更优雅些

SELECT 
   case 
     when HOUR(starttime) < 11 AND HOUR(endtime) = 11  then minute(endtime)
     when HOUR(starttime) < 11 AND HOUR(endtime) > 11  then 60
     when HOUR(starttime) = 11 AND HOUR(endtime) = 11  then minute(endtime) - minute(starttime)
     when HOUR(starttime) = 11 AND HOUR(endtime) > 11  then 60 - minute(starttime)
     else 0
   end AS ProcessTimeHour_11,
    case 
     when HOUR(starttime) < 12 AND HOUR(endtime) = 12  then minute(endtime)
     when HOUR(starttime) < 12 AND HOUR(endtime) > 12  then 60
     when HOUR(starttime) = 12 AND HOUR(endtime) = 12  then minute(endtime) - minute(starttime)
     when HOUR(starttime) = 12 AND HOUR(endtime) > 12  then 60 - minute(starttime)
     else 0
   end AS ProcessTimeHour_12
from StuffAndThings

我认为这是个好办法,但它很难看。也许有人能做得更优雅些

SELECT 
   case 
     when HOUR(starttime) < 11 AND HOUR(endtime) = 11  then minute(endtime)
     when HOUR(starttime) < 11 AND HOUR(endtime) > 11  then 60
     when HOUR(starttime) = 11 AND HOUR(endtime) = 11  then minute(endtime) - minute(starttime)
     when HOUR(starttime) = 11 AND HOUR(endtime) > 11  then 60 - minute(starttime)
     else 0
   end AS ProcessTimeHour_11,
    case 
     when HOUR(starttime) < 12 AND HOUR(endtime) = 12  then minute(endtime)
     when HOUR(starttime) < 12 AND HOUR(endtime) > 12  then 60
     when HOUR(starttime) = 12 AND HOUR(endtime) = 12  then minute(endtime) - minute(starttime)
     when HOUR(starttime) = 12 AND HOUR(endtime) > 12  then 60 - minute(starttime)
     else 0
   end AS ProcessTimeHour_12
from StuffAndThings
时差-

SELECT CAST(DATEADD(MINUTE,DATEDIFF(MINUTE,StartTime,EndTime),'2011-01-01 00:00:00.000') AS TIME)
as timeDifference 
from #YourTableName
日日夜夜

    declare @start_time as varchar(150);
    declare @end_time as varchar(150);
    set @start_time='2016-10-10 10:10';
    set @end_time='2016-10-12 12:10'

    SELECT datediff(day,@start_time,@end_time) as dayDifference,
CAST(DATEADD(MINUTE,DATEDIFF(MINUTE,@start_time,@end_time),'2011-01-01 00:00:00') AS TIME(0))
 as timeDifference
时差-

SELECT CAST(DATEADD(MINUTE,DATEDIFF(MINUTE,StartTime,EndTime),'2011-01-01 00:00:00.000') AS TIME)
as timeDifference 
from #YourTableName
日日夜夜

    declare @start_time as varchar(150);
    declare @end_time as varchar(150);
    set @start_time='2016-10-10 10:10';
    set @end_time='2016-10-12 12:10'

    SELECT datediff(day,@start_time,@end_time) as dayDifference,
CAST(DATEADD(MINUTE,DATEDIFF(MINUTE,@start_time,@end_time),'2011-01-01 00:00:00') AS TIME(0))
 as timeDifference

要处理一般情况,您可以尝试以下方法

    --drop table #processes 
CREATE TABLE #processes 
    (
    name  varchar(50),
    StartTime  Datetime,
    EndTime  DateTime
    );

    insert #processes VALUES('proc1','20161010 11:10','20161010 11:20');
    insert #processes VALUES('proc2','20161010 11:40','20161010 12:20');
    insert #processes VALUES('proc3','20161010 10:40','20161010 12:20');

;WITH HRS   AS  (SELECT 0 HR 
                UNION ALL
                SELECT HR + 1 FROM HRS WHERE HR < 23),
    MINS    AS  (SELECT 0 MN 
                UNION ALL
                SELECT MN + 1 FROM MINS WHERE MN < 59),
    TIMES   AS  (SELECT HR,MN FROM HRS CROSS JOIN MINS)
    SELECT name,starttime,endtime,Count(0) AS mins FROM #processes
                    JOIN TIMES 
                            ON (HR > datepart(hh,Starttime) 
                                OR HR = datepart(hh,Starttime)   AND MN >= datepart(n,STARTtIME))
                                AND 
                                (HR < datepart(hh, EndTime) 
                                OR HR = datepart(hh, EndTime)  AND MN < datepart(n,EndTime))

                    WHERE HR = 11 --hour is 11

        GROUP BY name,
                    starttime,
                    endtime                     



    drop table #processes;          

要处理一般情况,您可以尝试以下方法

    --drop table #processes 
CREATE TABLE #processes 
    (
    name  varchar(50),
    StartTime  Datetime,
    EndTime  DateTime
    );

    insert #processes VALUES('proc1','20161010 11:10','20161010 11:20');
    insert #processes VALUES('proc2','20161010 11:40','20161010 12:20');
    insert #processes VALUES('proc3','20161010 10:40','20161010 12:20');

;WITH HRS   AS  (SELECT 0 HR 
                UNION ALL
                SELECT HR + 1 FROM HRS WHERE HR < 23),
    MINS    AS  (SELECT 0 MN 
                UNION ALL
                SELECT MN + 1 FROM MINS WHERE MN < 59),
    TIMES   AS  (SELECT HR,MN FROM HRS CROSS JOIN MINS)
    SELECT name,starttime,endtime,Count(0) AS mins FROM #processes
                    JOIN TIMES 
                            ON (HR > datepart(hh,Starttime) 
                                OR HR = datepart(hh,Starttime)   AND MN >= datepart(n,STARTtIME))
                                AND 
                                (HR < datepart(hh, EndTime) 
                                OR HR = datepart(hh, EndTime)  AND MN < datepart(n,EndTime))

                    WHERE HR = 11 --hour is 11

        GROUP BY name,
                    starttime,
                    endtime                     



    drop table #processes;          

下面的示例将为每个源记录生成小时记录。它使用递归CTE从每个记录的开始时间移动到结束时间。它可能需要一些轻微的修改,以使其在您的情况下工作,但希望您能够了解此方法的工作原理

请注意,如下面的示例所示,即使时间跨度跨越日期边界,这也会正常工作

--==================================================================================
-- Do some quick setup to get a temporary table populated with data to use:
--==================================================================================
IF OBJECT_ID('tempdb..#ProcessHistory', 'U') IS NOT NULL DROP TABLE #ProcessHistory;
CREATE TABLE #ProcessHistory (
    Name VARCHAR(20),
    StartTime DATETIME,
    EndTime DATETIME
)

INSERT INTO #ProcessHistory
VALUES  ('process1', '2016-10-10 11:10', '2016-10-10 11:20'),
        ('process2', '2016-10-10 11:40', '2016-10-10 12:30'),
        ('process3', '2016-10-10 22:21', '2016-10-11 02:36');

--==================================================================================
-- Use a recursive CTE to generate hourly data for each record:
--==================================================================================
WITH HourlyData AS (
    -- Anchor:
    SELECT
        ph.Name [ProcessName],
        ph.StartTime [StartTime],
        ph.EndTime [EndTime],
        -- Get the current hour with date:
        DATEADD(MINUTE, -DATEPART(MINUTE, ph.StartTime), ph.StartTime) [CurrentHour],
        -- Calculate the next hour for use later:
        DATEADD(MINUTE, 60 - DATEPART(MINUTE, ph.StartTime), ph.StartTime) [NextHour],
        -- Determine how many minutes the process was active this hour:
        CASE
            WHEN DATEDIFF(MINUTE, ph.StartTime, ph.EndTime) > 60 - DATEPART(MINUTE, ph.StartTime)
                THEN 60 - DATEPART(MINUTE, ph.StartTime)
            ELSE DATEDIFF(MINUTE, ph.StartTime, ph.EndTime)
        END [Minutes]
    FROM #ProcessHistory ph

    UNION ALL

    -- Recurse:
    SELECT
        hd.ProcessName,
        hd.StartTime,
        hd.EndTime,
        hd.NextHour [CurrentHour],
        DATEADD(HOUR, 1, hd.NextHour) [NextHour],
        -- Determine how many minutes the process was active this hour:
        CASE
            WHEN DATEDIFF(MINUTE, hd.NextHour, hd.EndTime) < 60
                THEN DATEDIFF(MINUTE, hd.NextHour, hd.EndTime)
            ELSE 60
        END
    FROM HourlyData hd
    WHERE hd.NextHour < hd.EndTime
)
SELECT
    hd.ProcessName,
    hd.CurrentHour [HourWithDate],
    CONVERT(DATE, hd.CurrentHour) [Date],
    DATEPART(HOUR, hd.CurrentHour) [Hour],
    hd.Minutes
FROM HourlyData hd
ORDER BY
    hd.ProcessName,
    hd.CurrentHour;

下面的示例将为每个源记录生成小时记录。它使用递归CTE从每个记录的开始时间移动到结束时间。它可能需要一些轻微的修改,以使其在您的情况下工作,但希望您能够了解此方法的工作原理

请注意,如下面的示例所示,即使时间跨度跨越日期边界,这也会正常工作

--==================================================================================
-- Do some quick setup to get a temporary table populated with data to use:
--==================================================================================
IF OBJECT_ID('tempdb..#ProcessHistory', 'U') IS NOT NULL DROP TABLE #ProcessHistory;
CREATE TABLE #ProcessHistory (
    Name VARCHAR(20),
    StartTime DATETIME,
    EndTime DATETIME
)

INSERT INTO #ProcessHistory
VALUES  ('process1', '2016-10-10 11:10', '2016-10-10 11:20'),
        ('process2', '2016-10-10 11:40', '2016-10-10 12:30'),
        ('process3', '2016-10-10 22:21', '2016-10-11 02:36');

--==================================================================================
-- Use a recursive CTE to generate hourly data for each record:
--==================================================================================
WITH HourlyData AS (
    -- Anchor:
    SELECT
        ph.Name [ProcessName],
        ph.StartTime [StartTime],
        ph.EndTime [EndTime],
        -- Get the current hour with date:
        DATEADD(MINUTE, -DATEPART(MINUTE, ph.StartTime), ph.StartTime) [CurrentHour],
        -- Calculate the next hour for use later:
        DATEADD(MINUTE, 60 - DATEPART(MINUTE, ph.StartTime), ph.StartTime) [NextHour],
        -- Determine how many minutes the process was active this hour:
        CASE
            WHEN DATEDIFF(MINUTE, ph.StartTime, ph.EndTime) > 60 - DATEPART(MINUTE, ph.StartTime)
                THEN 60 - DATEPART(MINUTE, ph.StartTime)
            ELSE DATEDIFF(MINUTE, ph.StartTime, ph.EndTime)
        END [Minutes]
    FROM #ProcessHistory ph

    UNION ALL

    -- Recurse:
    SELECT
        hd.ProcessName,
        hd.StartTime,
        hd.EndTime,
        hd.NextHour [CurrentHour],
        DATEADD(HOUR, 1, hd.NextHour) [NextHour],
        -- Determine how many minutes the process was active this hour:
        CASE
            WHEN DATEDIFF(MINUTE, hd.NextHour, hd.EndTime) < 60
                THEN DATEDIFF(MINUTE, hd.NextHour, hd.EndTime)
            ELSE 60
        END
    FROM HourlyData hd
    WHERE hd.NextHour < hd.EndTime
)
SELECT
    hd.ProcessName,
    hd.CurrentHour [HourWithDate],
    CONVERT(DATE, hd.CurrentHour) [Date],
    DATEPART(HOUR, hd.CurrentHour) [Hour],
    hd.Minutes
FROM HourlyData hd
ORDER BY
    hd.ProcessName,
    hd.CurrentHour;

谢谢@Soukai这似乎是在耍花招,或者至少是给我指出了正确的方向。谢谢@Soukai这似乎是在耍花招,或者至少是给我指出了正确的方向。