将重叠时间段外推到之前,重叠和之后的vin SQL

时间:2014-09-08 13:37:12

标签: sql sql-server date sql-server-2012 overlapping

我的数据包含不同行的重叠日期。对于包含重叠的每两行,我需要按照以下方式对其进行适当的分解。

首先,数据如下所示:

EMPID FIRSTNAME SURNAME ACTIVITY  START_DATE          END_DATE            HOURS_PER_DAY STATION
101   ANDREW    SMITH   AVAILABLE 2013-07-08 09:00:00 2013-07-08 17:00:00 8.00             LONDON
101   ANDREW    SMITH   SICKNESS  2013-07-08 07:00:00 2013-07-08 12:00:00 5.00             LONDON

原因是数据最初来自两个独立的表,我已将两个表的内容插入一个。

此数据最终将按人数分组,提供“每日小时数”列。在上表中,这个人将有13个小时,但正如我们在上面所看到的,两个时期的时间跨度只有10个小时。

在上面的例子中,我需要将结果分成3行 - 重叠前的位,重叠和重叠后的位:

EMPID  NAME ACTIVITY  START_DATE          END_DATE            HOURS_PER_DAY STATION
101   JOHN  SICKNESS  2013-07-08 07:00:00 2013-07-08 09:00:00 2             LONDON
101   JOHN  SICKNESS  2013-07-08 09:00:00 2013-07-08 12:00:00 3             LONDON
101   JOHN  AVAILABLE 2013-07-08 12:00:00 2013-07-08 17:00:00 5             LONDON

对于重叠的时间段必须归类为疾病。请注意除了可用和疾病之外还有其他选择,但唯一重叠的是疾病与任何其他类型,例如'疾病'和'可用'之间的冲突或'疾病'和'训练'之间的冲突。

此外,数据已被分为24小时 - 即我已经将4天内的疾病期推断为4个不同的行,这就是为什么每天的小时数列永远不会超过24小时 - 如果满了如果存在24小时,则结束日期将在开始日期后的1天内完成 - 开始日期和结束日期均为午夜。当我尝试执行所需的操作时,我尝试按EMPID,NAME,CAST(START_DATE)AS DATE,CAST(END_DATE AS DATE)和STATION对数据进行分组。这些是确定需要比较的分组的适当字段。

请注意目前约有。 2500行数据与提供的数据相似,并且可能存在以下类型的重叠(如果AVAILABLE条目从09:00开始并在17:00结束 - 请注意,我不是仅仅使用它作为示例:

  • SICKNESS和AVAILABLE在完全相同的时间开始和结束 - 例如疾病从09:00开始,到17:00结束(结果8小时SICKNESS)
  • SICKNESS在AVAILABLE条目之前开始并在其中间结束:例如疾病从07:00开始,到12:00结束(结果:2小时SICKNESS,3小时SICKNESS重叠,5小时可用)
  • SICKNESS在AVAILABLE条目的中间开始,在AVAILABLE条目之后结束,例如疾病从12:00开始,到22:00结束(结果:3小时可用,重叠5小时,5小时可用)
  • SICKNESS在AVAILABLE条目期间开始并在AVAILABLE条目期间结束,例如疾病从11:00开始,到14:00结束(结果:2小时可用,3小时SICKNESS重叠,3小时可用)
  • a SICKNESS在AVAILABLE条目之前开始,在AVAILABLE条目之后结束,例如疾病从06:00开始到18:00结束(结果:12小时疾病)
  • 疾病从AVAILABLE入口中途开始,同时结束
  • 疾病从AVAILABLE条目的中途开始,在AVAILABLE条目中结束。

请再次注意'AVAILABLE'不是唯一的选择。

我的查询目前正在以这篇文章顶部的格式返回数据,该格式存储在临时表@INDIVIDUALDAYS中 - 我现在想做@INDIVIDUALDAYS所需的任何内容来将其外推为描述上方。

我希望以完全相同的格式返回相同列的数据(只需外推到多行,因为我需要对它进行一些进一步的操作和计算。

如果需要,我很乐意提供我当前的代码,但它超过200行,我相信我已经给了你足够的信息

以下是一些涵盖上述7种不同渗透的样本数据:

101 Andrew  Smith   Available   2014-08-19 09:00:00.000 2014-08-19 17:00:00.000 8.00    London
101 Andrew  Smith   SICKNESS    2014-08-19 09:00:00.000 2014-08-19 17:00:00.000 8.00    London
101 Andrew  Smith   SICKNESS    2014-08-20 12:00:00.000 2014-08-20 19:00:00.000 7.00    London
101 Andrew  Smith   Available   2014-08-20 09:00:00.000 2014-08-20 17:00:00.000 8.00    London
101 Andrew  Smith   Available   2014-08-21 09:00:00.000 2014-08-21 17:00:00.000 8.00    London
101 Andrew  Smith   SICKNESS    2014-08-21 04:00:00.000 2014-08-21 12:00:00.000 8.00    London
101 Andrew  Smith   SICKNESS    2014-08-22 06:00:00.000 2014-08-22 18:00:00.000 12.00   London
101 Andrew  Smith   Available   2014-08-22 09:00:00.000 2014-08-22 17:00:00.000 8.00    London
101 Andrew  Smith   Available   2014-08-23 09:00:00.000 2014-08-23 17:00:00.000 8.00    London
101 Andrew  Smith   SICKNESS    2014-08-23 11:00:00.000 2014-08-23 14:00:00.000 3.00    London
101 Andrew  Smith   Available   2014-08-24 09:00:00.000 2014-08-23 17:00:00.000 8.00    London
101 Andrew  Smith   SICKNESS    2014-08-24 09:00:00.000 2014-08-23 14:00:00.000 3.00    London
101 Andrew  Smith   Available   2014-08-25 09:00:00.000 2014-08-23 17:00:00.000 8.00    London
101 Andrew  Smith   SICKNESS    2014-08-25 11:00:00.000 2014-08-23 17:00:00.000 3.00    London

1 个答案:

答案 0 :(得分:0)

要做到这一点,首先需要将两行组合在一起作为1行。将所有数据作为单行存储后,可以执行一系列联合查询来构建结果行,每个条件都有一个查询。

这会构建测试数据:

INSERT INTO TData
    ([ID], [FName], [LName], [Status], [StartTime], [EndTime], [Hours], [Location])
VALUES
    (101, 'Andrew', 'Smith', 'Available', '2014-08-19 09:00:00', '2014-08-19 17:00:00', 8.00, 'London'),
    (101, 'Andrew', 'Smith', 'SICKNESS', '2014-08-19 09:00:00', '2014-08-19 17:00:00', 8.00, 'London'),
    (101, 'Andrew', 'Smith', 'SICKNESS', '2014-08-20 12:00:00', '2014-08-20 19:00:00', 7.00, 'London'),
    (101, 'Andrew', 'Smith', 'Available', '2014-08-20 09:00:00', '2014-08-20 17:00:00', 8.00, 'London'),
    (101, 'Andrew', 'Smith', 'Available', '2014-08-21 09:00:00', '2014-08-21 17:00:00', 8.00, 'London'),
    (101, 'Andrew', 'Smith', 'SICKNESS', '2014-08-21 04:00:00', '2014-08-21 12:00:00', 8.00, 'London'),
    (101, 'Andrew', 'Smith', 'SICKNESS', '2014-08-22 06:00:00', '2014-08-22 18:00:00', 12.00, 'London'),
    (101, 'Andrew', 'Smith', 'Available', '2014-08-22 09:00:00', '2014-08-22 17:00:00', 8.00, 'London'),
    (101, 'Andrew', 'Smith', 'Available', '2014-08-23 09:00:00', '2014-08-23 17:00:00', 8.00, 'London'),
    (101, 'Andrew', 'Smith', 'SICKNESS', '2014-08-23 11:00:00', '2014-08-23 14:00:00', 3.00, 'London'),
    (101, 'Andrew', 'Smith', 'Available', '2014-08-24 09:00:00', '2014-08-23 17:00:00', 8.00, 'London'),
    (101, 'Andrew', 'Smith', 'SICKNESS', '2014-08-24 09:00:00', '2014-08-23 14:00:00', 3.00, 'London'),
    (101, 'Andrew', 'Smith', 'Available', '2014-08-25 09:00:00', '2014-08-23 17:00:00', 8.00, 'London'),
    (101, 'Andrew', 'Smith', 'SICKNESS', '2014-08-25 11:00:00', '2014-08-23 17:00:00', 3.00, 'London')
;

这是结果的开始。您需要为最终显示的每个行/条件添加更多UNION子句。

;WITH Combined AS (
SELECT T1.*, t2.StartTime AS S_StartTime, t2.EndTime AS S_EndTime, 
        t2.Status AS S_Status, t2.Hours AS S_Hours
FROM TData T1 --Change TData to your table name
LEFT OUTER JOIN Tdata T2 ON T1.id = T2.id 
        AND CAST(T1.StartTime AS date) = CAST(T2.StartTime as date) 
        AND t1.Status <> t2.Status
WHERE T1.Status <> 'SICKNESS' 
)
--this is case 1 Show sickness only?  If not, add another row
SELECT ID, FName, LName, s_Status AS Status, 
        s_StartTime AS StartTime, s_EndTime AS EndTime, 
        S_Hours AS Hours, Location
FROM combined 
WHERE StartTime = S_StartTime and EndTime = s_EndTime 
UNION --Case 2 Row 1
SELECT ID, FName, LName, s_Status AS Status, 
        s_StartTime AS StartTime, StartTime AS EndTime, 
        DATEDIFF(minute,S_StartTime,StartTime)/60 AS Hours, Location
FROM combined 
WHERE S_StartTime < StartTime 
      AND S_EndTime BETWEEN StartTime AND EndTime 
UNION --case 2 row 2
SELECT ID, FName, LName, S_Status AS Status, 
       StartTime AS StartTime, S_EndTime AS EndTime, 
       DATEDIFF(minute,StartTime,S_EndTime)/60 AS Hours, Location
FROM combined 
WHERE S_StartTime < StartTime 
      AND S_EndTime BETWEEN StartTime AND EndTime 
UNION --case 2 row 3
SELECT ID, FName, LName, Status, 
       S_EndTime AS StartTime, EndTime AS EndTime, 
       DATEDIFF(minute,S_EndTime,EndTime)/60 AS Hours, Location
FROM combined 
WHERE S_StartTime < StartTime 
      AND S_EndTime BETWEEN StartTime AND EndTime 

我可以解决其余的条款,但应该很清楚如何做到这一点。如果您需要其他帮助,请与我们联系。