Это немного утомительно в 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