根据时间持续时间拆分记录

时间:2016-03-21 15:54:16

标签: sql-server tsql

我已经得到了这张表格,其中包含了我们呼叫中心代理商在各州所花费的时间。 以下是其中一条记录的示例:

AgentName, AgentState, BeginTransitionTime, EndTransitionTime, BeginHour,   EndHour

Breana Rascon(994840), Work Time, 3/14/16 7:56:19 AM, 3/14/16 11:02:51 AM, 7,   11

我希望以上记录最终分成5条记录,如下:

Breana Rascon(994840), Work Time, 3/14/16 7:56:19 AM, 3/14/2016 7:59:59 AM, 7,  7

Breana Rascon(994840), Work Time, 3/14/16 8:00:00 AM, 3/14/2016 8:59:59 AM, 8,  8

Breana Rascon(994840), Work Time, 3/14/16 9:00:00 AM, 3/14/2016 9:59:59 AM, 9,  9

Breana Rascon(994840), Work Time, 3/14/16 10:00:00 AM, 3/14/2016 10:59:59 AM,   10, 10

Breana Rascon(994840), Work Time, 3/14/16 11:00:00 AM, 3/14/16 11:02:51 AM, 11, 11

我开始使用光标,当记录被分割超过2小时时工作得很好,但不止于此而且代码开始失控。任何帮助都将受到高度赞赏。

谢谢!

2 个答案:

答案 0 :(得分:0)

如果你使用数字表,那么这是一个简单的连接和一些转换。否则你需要一个CTE或其他一些窗口函数。

numberz表

DECLARE @UpperLimit INT = 1000000;

IF OBJECT_ID('dbo.numberz','U') IS NULL 
BEGIN
    CREATE TABLE dbo.numberz (numVal INT);

    WITH n(rn) AS
    (
      SELECT ROW_NUMBER() OVER (ORDER BY s1.[object_id])
      FROM sys.all_columns AS s1
      CROSS JOIN sys.all_columns AS s2
    )
    INSERT dbo.numberz
    SELECT [numVAl] = 0
    UNION ALL
    SELECT rn
    FROM n
    WHERE rn <= @UpperLimit;

    CREATE UNIQUE CLUSTERED INDEX uix_numVal ON dbo.numberz([numVAl]);
END

表格创建

CREATE TABLE tbl_agentTime
(
      AgentName           NVARCHAR(255)
    , AgentState          NVARCHAR(255)
    , BeginTransitionTime DATETIME
    , EndTransitionTime   DATETIME
    , BeginHour           INT
    , EndHour             INT
)

INSERT tbl_agentTime
VALUES ('BREANA RASCON(994840)', 'WORK TIME', '2016-03-14 7:56:19', '2016-03-14 11:02:51', 7, 11)

记录拆分

select 
      AgentName
    , AgentState
    , BeginTransitionTime = CASE WHEN numVal = BeginHour then BeginTransitionTime else cast(cast(BeginTransitionTime as date) as nvarchar(10)) +' '+cast(numVal as nvarchar(2))+':00:00' end 
    , EndTransitionTime   = CASE WHEN numVal = EndHour   then EndTransitionTime   else cast(cast(ENDTRANSITIONTIME   as date) as nvarchar(10)) +' '+cast(numVal as nvarchar(2))+':59:59' end 
    , BeginHour           = numVal
    , EndHour             = numVal
from tbl_agentTime a
    join numberz n on n.numVal >= a.BeginHour and n.numVal<= a.EndHour

答案 1 :(得分:0)

如果你想使用递归CTE,它看起来像这样......

WITH    cte
          AS (SELECT    [AgentName],
                        [AgentState],
                        [BeginTransitionTime],
                        [EndTransitionTime],
                        [NewEndTransitionTime] = DATEADD(second,-1,DATEADD(hour,DATEDIFF(hour,0,[BeginTransitionTime]) + 1,0)),
                        [BeginHour],
                        [EndHour] = [BeginHour]
              FROM      agents
              UNION ALL
              SELECT    [AgentName],
                        [AgentState],
                        DATEADD(hour,DATEDIFF(hour,0,[NewEndTransitionTime]) + 1,0),
                        [EndTransitionTime],
                        [NewEndTransitionTime] = CASE WHEN [EndTransitionTime] < [NewEndTransitionTime] THEN [EndTransitionTime]
                                                      ELSE DATEADD(second,-1,DATEADD(hour,DATEDIFF(hour,0,[NewEndTransitionTime]) + 2,0))
                                                 END,
                        [BeginHour] + 1,
                        [EndHour] + 1
              FROM      cte
              WHERE     DATEADD(hour,DATEDIFF(hour,0,[NewEndTransitionTime]) + 1,0) < [EndTransitionTime]
             )
    SELECT  [AgentName],
            [AgentState],
            [BeginTransitionTime],
            [EndTransitionTime] = CASE WHEN [EndTransitionTime] < [NewEndTransitionTime] THEN [EndTransitionTime] ELSE [NewEndTransitionTime] END,
            [BeginHour],
            [EndHour]
    FROM    cte

SQL Fiddle Demo

这也可以使用数字表来完成。虽然只有少量记录,但速度较慢,但​​对于较大的数据集,速度可能会更快。

WITH    E1(N)
          AS (SELECT    1
              UNION ALL
              SELECT    1
              UNION ALL
              SELECT    1
              UNION ALL
              SELECT    1
              UNION ALL
              SELECT    1
             ),                          
        E2([Hour])
          AS (SELECT    ROW_NUMBER() OVER (ORDER BY (SELECT NULL
                                                    )) Num
              FROM      E1 a,
                        E1 b
             )
    SELECT  [AgentName],
            [AgentState],
            [BeginTransitionTime] = CASE WHEN a.BeginHour = E2.[Hour] 
                                        THEN [BeginTransitionTime] 
                                        ELSE DATEADD(hour,DATEDIFF(hour,0,[BeginTransitionTime]) + (E2.[Hour] - a.BeginHour),0) 
                                    END,
            [EndTransitionTime] =   CASE WHEN [EndTransitionTime] < DATEADD(second, -1 , DATEADD(hour,DATEDIFF(hour,0,[BeginTransitionTime]) + (E2.[Hour] - a.BeginHour + 1),0))
                                        THEN [EndTransitionTime] 
                                        ELSE DATEADD(second, -1 , DATEADD(hour,DATEDIFF(hour,0,[BeginTransitionTime]) + (E2.[Hour] - a.BeginHour + 1),0))
                                    END,
            [BeginHour] = E2.[Hour],
            [EndHour] = E2.[Hour]
    FROM    agents a
            JOIN E2 ON E2.[Hour] BETWEEN a.BeginHour AND a.EndHour

SQL Fiddle Demo

相关问题