Найти недостающие диапазоны дат - PullRequest
0 голосов
/ 23 сентября 2011

Таблица 1

code        StartDate        EndDate
A           01/01/2011        06/15/2011
A           06/25/2011        06/30/2011
B           01/12/2011        07/31/2011
B           08/3/2011         12/31/2011

Таблица 2

code        StartDate        EndDate
A           01/01/2011       06/30/2011
B           01/12/2011        07/31/2011
B           08/3/2011         12/25/2011

Мне нужно найти то, что находится в Таблице 1, а не в Таблице 2, что составляет

code        StartDate        EndDate
B           12/26/2011        12/31/2011

И наобороттого, что находится в Таблице 2, а не в Таблице 1

code        StartDate        EndDate
A           06/16/2011       06/29/2011

В поле даты нет компонента времени, и предпочтительным является T-SQL (SQL Server 2000).

1 Ответ

5 голосов
/ 23 сентября 2011

Это немного утомительно в SQL Server 2000. Он использует таблицу чисел для расширения диапазонов дат в отдельные строки.Затем NOT EXISTS для анти-полусоединения затем использует подход «островов», который я украл из статьи MSDN, чтобы снова свести результат обратно в диапазоны.

SET DATEFORMAT MDY

DECLARE @Numbers TABLE (N INT PRIMARY KEY)

INSERT INTO @Numbers
SELECT number
FROM master..spt_values
WHERE type='P' AND number >= 0


DECLARE @Table1 TABLE
(
code CHAR(1),
StartDate DATETIME,
EndDate DATETIME
)
DECLARE @Table2 TABLE
(
code CHAR(1),
StartDate DATETIME,
EndDate DATETIME
)
INSERT INTO @Table1
SELECT 'A','01/01/2011','06/15/2011' UNION ALL
SELECT 'A','06/25/2011','06/30/2011' UNION ALL
SELECT 'B','01/12/2011','07/31/2011' UNION ALL
SELECT 'B','08/3/2011',' 12/31/2011'

INSERT INTO @Table2
SELECT 'A','01/01/2011','06/30/2011' UNION ALL
SELECT 'B','01/12/2011','07/31/2011' UNION ALL
SELECT 'B','08/3/2011',' 12/25/2011'

DECLARE @Results TABLE
(
code CHAR(1),
StartDate DATETIME
)

INSERT INTO @Results
SELECT T1.code,
       DATEADD(DAY, N, StartDate)
FROM   @Table1 T1
       INNER JOIN @Numbers N1
         ON N <= DATEDIFF(DAY, StartDate, EndDate)
WHERE  NOT EXISTS (SELECT *
                   FROM   @Table2 T2
                          INNER JOIN @Numbers N2
                            ON N2.N <= DATEDIFF(DAY, T2.StartDate, T2.EndDate)
                   WHERE  DATEADD(DAY, N1.N, T1.StartDate) =
                          DATEADD(DAY, N2.N, T2.StartDate)
                          AND T1.code = T2.code)  

/*SQL Server 2000 gaps and islands approach from here 
http://msdn.microsoft.com/en-us/library/aa175780%28v=sql.80%29.aspx*/
SELECT t1.code,
       t1.StartDate,
       MIN(t2.StartDate) AS EndDate
FROM   (SELECT StartDate,
               code
        FROM   @Results tbl1
        WHERE  NOT EXISTS(SELECT *
                          FROM   @Results tbl2
                          WHERE  tbl1.StartDate = tbl2.StartDate + 1
                                 AND tbl1.code = tbl2.code)) t1
       INNER JOIN (SELECT StartDate,
                          code
                   FROM   @Results tbl1
                   WHERE  NOT EXISTS(SELECT *
                                     FROM   @Results tbl2
                                     WHERE  tbl2.StartDate = tbl1.StartDate + 1
                                            AND tbl1.code = tbl2.code)) t2
         ON t1.StartDate <= t2.StartDate
         AND t1.code = t2.code
GROUP  BY t1.code,
          t1.StartDate  
...