用sql查找时隙

时间:2015-05-26 01:51:36

标签: sql sql-server sql-server-2008 datetime

我有一个场景(SQL 2008),我需要从下表中找到占用的时间帧/非间隙。例如。我创建了这个虚拟表。

CREATE TABLE Job
(
JobID INT NOT NULL,
  WorkerID INT NOT NULL,
  JobStart DATETIME NOT NULL,
  JobEnd DATETIME NOT NULL
);

INSERT INTO Job (JobID, WorkerID, JobStart, JobEnd)
    VALUES (1, 25, '2012-11-17 16:00', '2012-11-17 17:00'),
        (2, 25, '2012-11-17 16:00', '2012-11-17 16:50'),
        (3, 25, '2012-11-19 18:00', '2012-11-19 18:30'),
        (4, 25, '2012-11-19 17:30', '2012-11-19 18:10'),
        (5, 26, '2012-11-18 16:00', '2012-11-18 17:10'),
        (6, 26, '2012-11-18 16:00', '2012-11-19 16:50');

所以为此,qry shd返回这样的数据:

WorkerID | StartDate | EndDate
25      2012-11-17 16:00   2012-11-17 17:00
25      2012-11-17 17:30   2012-11-17 18:30
26      2012-11-18 16:00    2012-11-18 17:10

我能够得到结果,但我正在使用while循环,它是一个非常迭代的方法。任何机会,我可以避免使用while获得结果

1 个答案:

答案 0 :(得分:4)

这是一个Packing Date and Time Interval问题。 Itzik Ben-Gan发表了article,为这个问题提供了许多解决方案。使用Itzik的解决方案之一,这是一个解决您的问题的查询:

SQL Fiddle

WITH C1 AS(
    SELECT
        JobID, WorkerId, JobStart AS ts, +1 AS type, NULL AS e,
        ROW_NUMBER() OVER(PARTITION BY WorkerId ORDER BY JobStart, JobId) AS s
    FROM Job
    UNION ALL
    SELECT
        JobID, WorkerId, JobEnd AS ts, -1 AS type,
        ROW_NUMBER() OVER(PARTITION BY WorkerId ORDER BY JobEnd, JobId) AS e,
        NULL AS s
    FROM Job
),
C2 AS(
    SELECT *,
        ROW_NUMBER() OVER(PARTITION BY WorkerId ORDER BY ts, type DESC, JobId) AS se
    FROM C1
),
C3 AS(
    SELECT ts, WorkerId,
        FLOOR((ROW_NUMBER() OVER(PARTITION BY WorkerId ORDER BY ts) - 1) / 2 + 1) AS grpnum
    FROM C2
    WHERE COALESCE(s - (se - s) - 1, (se - e) - e) = 0
)
SELECT 
    WorkerId,
    MIN(ts) AS StartDate,
    MAX(ts) AS EndDate
FROM C3
GROUP BY WorkerID, grpnum
ORDER BY WorkerID

<强>结果

WorkerId    StartDate               EndDate
----------- ----------------------- -----------------------
25          2012-11-17 16:00:00.000 2012-11-17 17:00:00.000
25          2012-11-19 17:30:00.000 2012-11-19 18:30:00.000
26          2012-11-18 16:00:00.000 2012-11-19 16:50:00.000