与第一个可用的泳道重叠的时间

时间:2017-10-05 13:10:59

标签: sql sql-server-2008 tsql

我正在尝试为报告设置一个数据集,要求在所谓的泳道中显示某些任务,即当重叠2次时,它们会在报告中的2个不同的行上显示,并且不会在视觉上重叠(在同一行)。

到目前为止,我已经对基础知识进行了排序,但是在链条的末端与开头不重叠的情况下,链条会多次重叠会变得复杂。

此外,数据分为不同的类别。我觉得只需要包含一个(频道)来显示该功能。

到目前为止,这是我的代码:

DECLARE @TempTable TABLE
(
    StartTime   DATETIME
    ,Duration   INT
    ,Id         INT
    ,Channel    INT
)

INSERT INTO @TempTable(StartTime, Duration, Id, Channel)
VALUES('2017-10-05 00:30:32', 1827, 261832091, 2)
INSERT INTO @TempTable(StartTime, Duration, Id, Channel)
VALUES('2017-10-05 00:34:53', 1686, 265169258, 3)
INSERT INTO @TempTable(StartTime, Duration, Id, Channel)
VALUES('2017-10-05 00:44:16', 403, 136756869, 3)
INSERT INTO @TempTable(StartTime, Duration, Id, Channel)
VALUES('2017-10-05 00:50:45', 2112, 493664900, 2)
INSERT INTO @TempTable(StartTime, Duration, Id, Channel)
VALUES('2017-10-05 00:54:44', 1459, 356826302, 2)
INSERT INTO @TempTable(StartTime, Duration, Id, Channel)
VALUES('2017-10-05 00:55:01', 2620, 441592787, 3)
INSERT INTO @TempTable(StartTime, Duration, Id, Channel)
VALUES('2017-10-05 01:05:32', 546, 62903133, 3)

SELECT Swimlane
,StartTime
,EndTime
,Id
,Channel

FROM (
    SELECT CASE WHEN tt.id = tt2.id THEN ROW_NUMBER() OVER (PARTITION BY tt.id, tt2.Channel ORDER BY tt.StartTime, tt2.StartTime, tt2.Channel) ELSE NULL END AS 'Swimlane'
    ,tt.StartTime
    ,DATEADD(SECOND, tt.Duration, tt.StartTime) AS 'EndTime'
    ,tt.Id
    ,tt.Channel
    ,tt2.StartTime AS 'StartTime2'
    ,DATEADD(SECOND, tt2.Duration, tt2.StartTime) AS 'EndTime2'
    ,tt2.Id AS 'Id2'
    ,tt2.Channel AS 'Channel2'

    FROM @TempTable tt
    LEFT JOIN @TempTable tt2 ON tt.StartTime >= tt2.StartTime
        AND DATEADD(SECOND, tt.Duration, tt.StartTime) >= tt2.StartTime
        AND DATEADD(SECOND, tt2.Duration, tt2.StartTime) >= tt.StartTime
        AND tt.Channel = tt2.Channel
) a

WHERE a.Swimlane IS NOT NULL

ORDER BY StartTime

这给出了结果:

Swimlane StartTime             EndTime               Id          Channel
1        2017-10-05 00:30:32   2017-10-05 01:00:59   261832091   2
1        2017-10-05 00:34:53   2017-10-05 01:02:59   265169258   3
2        2017-10-05 00:44:16   2017-10-05 00:50:59   136756869   3
2        2017-10-05 00:50:45   2017-10-05 01:25:57   493664900   2
3        2017-10-05 00:54:44   2017-10-05 01:19:03   356826302   2
2        2017-10-05 00:55:01   2017-10-05 01:38:41   441592787   3
2        2017-10-05 01:05:32   2017-10-05 01:14:38   62903133    3

它完美地适用于此处最后一行与前一行最后一行的位置,因为它只与前一行重叠,而不是前一行。 最后一排应该最后排在泳道1上,因为它是空的,但是如果我把它放到泳道3上,我也很满意。

我希望这是有道理的。这对我来说很有意义,但是我已经坚持了很长一段时间,所以我可能会瞪大一些我应该解释的东西。

这里的所有数据当然只是随机噪音,但我相信这些数据充分显示了我的问题。

1 个答案:

答案 0 :(得分:1)

您可以将Swimlane添加到临时表并将其初始化为1.只要发现冲突,您就可以增加它。如果只有3个通道可用,则可以将4转换为null。

部分解决方案

DECLARE @TempTable TABLE
(
    StartTime   DATETIME
    ,Duration   INT
    ,Id         INT
    ,Channel    INT
    ,Swimlane   tinyint default 1
    ,EndTime    as  DATEADD(SECOND, Duration, StartTime)
)

INSERT INTO @TempTable(StartTime, Duration, Id, Channel)
VALUES('2017-10-05 00:30:32', 1827, 261832091, 2)
INSERT INTO @TempTable(StartTime, Duration, Id, Channel)
VALUES('2017-10-05 00:34:53', 1686, 265169258, 3)
INSERT INTO @TempTable(StartTime, Duration, Id, Channel)
VALUES('2017-10-05 00:44:16', 403, 136756869, 3)
INSERT INTO @TempTable(StartTime, Duration, Id, Channel)
VALUES('2017-10-05 00:50:45', 2112, 493664900, 2)
INSERT INTO @TempTable(StartTime, Duration, Id, Channel)
VALUES('2017-10-05 00:54:44', 1459, 356826302, 2)
INSERT INTO @TempTable(StartTime, Duration, Id, Channel)
VALUES('2017-10-05 00:55:01', 2620, 441592787, 3)
INSERT INTO @TempTable(StartTime, Duration, Id, Channel)
VALUES('2017-10-05 01:05:32', 546, 62903133, 3)


while 1=1 begin
    update  conflict
    set Swimlane    =   nullif(conflict.Swimlane+1,4)
    FROM            @TempTable  as  booking
        inner join  @TempTable  as  conflict
            on  conflict.Id         >   booking.Id
            and conflict.Channel    =   booking.Channel
            and conflict.Swimlane   =   booking.Swimlane
            and (   conflict.StartTime  between booking.StartTime and booking.EndTime
                or  conflict.EndTime    between booking.StartTime and booking.EndTime
                or  booking.StartTime   between conflict.StartTime and conflict.EndTime
                or  booking.EndTime     between conflict.StartTime and conflict.EndTime
            )
    ;

    if @@ROWCOUNT <= 0 break;
end


SELECT 
    Swimlane
,   StartTime
,   EndTime
,   Id
,   Channel
from    @TempTable
ORDER BY    StartTime
;

已知问题

如果发生冲突,则始终会移动更大的ID。在下面的例子中,我们应该在第2道上放置ID 2和4,而不是2&amp; 3(当前解决方案)。

==============  id:1  time:1-5  lane:1     correct:1
=======         id:2  time:1-3  lane:2     correct:2
       =======  id:4  time:3-5  lane:3     correct:2
=====           id:5  time:1-2  lane:3     correct:3
         =====  id:3  time:4-5  lane:2     correct:3
     ====       id:6  time:2-4  lane:null  correct:3

如果我们用最早的非冲突预订填充车道,它应该会更好。