查找两个日期之间的重叠天数

时间:2018-09-24 14:22:36

标签: sql-server tsql

我有两个表,每个表都保存日期范围(从date1到date2)

我将在表1和表2中的两个日期之间找到重叠的天

示例

table1
-------------------------
id   |  FromDate | ToDate
1    |2000-01-01 | 2000-02-04
2    |2000-03-01 | 2000-03-29

table2
-------------------------
id   | FromDate  | ToDate
1    |2000-02-01 | 2000-02-07
2    |2000-03-27 | 2000-03-29

我想要的结果:

2000-02-01
2000-02-02
2000-02-03
2000-02-04
2000-03-27
2000-03-28
2000-03-29

3 个答案:

答案 0 :(得分:1)

这应该有效:

CREATE TABLE #t1 
(
  id int,
  FromDate date,
  ToDate date
)
CREATE TABLE #t2
(
  id int,
  FromDate date,
  ToDate date
)

INSERT #t1 VALUES 
(1, '2000-01-01', '2000-02-04'),
(2, '2000-03-01', '2000-03-29')

INSERT #t2 VALUES 
(1, '2000-02-01', '2000-02-07'),
(2, '2000-03-27', '2000-03-29')

WITH DateRange AS --select range where intersection is possible
(
    SELECT MAX(MinDate) MinDate,MIN(MaxDate) MaxDate,DATEDIFF(DAY,MAX(MinDate),MIN(MaxDate)) Diff
    FROM (VALUES ((SELECT MIN(FromDate) FROM #t1)),((SELECT MIN(FromDate) FROM #t2))) MinDate(MinDate)
    CROSS APPLY (VALUES ((SELECT MAX(ToDate) FROM #t1)),((SELECT MAX(ToDate) FROM #t2))) MaxDate(MaxDate)
), AllDates AS --generate sequence of days
(
    SELECT MinDate D, MaxDate Limit
    FROM DateRange
    UNION ALL
    SELECT DATEADD(DAY, 1, D), Limit
    FROM AllDates
    WHERE DATEADD(DAY, 1, D)<=Limit
) --select all days existing in any range in both tables
SELECT D
FROM AllDates
WHERE EXISTS (SELECT * FROM #t1 WHERE D>=FromDate AND D<=ToDate)
  AND EXISTS (SELECT * FROM #t2 WHERE D>=FromDate AND D<=ToDate)

答案 1 :(得分:1)

可以通过CTE和递归来做到这一点。

--Your sample data
DECLARE @table1 TABLE (id int PRIMARY KEY, FromDate date, ToDate date)
DECLARE @table2 TABLE (id int PRIMARY KEY, FromDate date, ToDate date)
INSERT INTO @table1 VALUES (1, '2000-01-01', '2000-02-04') , (2, '2000-03-01', '2000-03-29')
INSERT INTO @table2 VALUES (1, '2000-02-01', '2000-02-07') , (2, '2000-03-27', '2000-03-29')

--A couple CTE's
;WITH cteDates AS (        
SELECT T1.id --get the min and max dates for each id
      ,CASE WHEN T1.FromDate > T2.FromDate THEN T1.FromDate ELSE T2.FromDate END [mindate]
      ,CASE WHEN T1.ToDate < T2.ToDate THEN T1.ToDate ELSE T2.ToDate END [maxdate]    
  FROM @table1 T1 INNER JOIN @table2 T2 ON T1.id = T2.id
)

, cteRecursion AS ( --date range for each id
SELECT id, mindate AS DateValue
  FROM cteDates

UNION ALL

SELECT id, DATEADD(DAY, 1, DateValue)
  FROM cteRecursion C1
 WHERE DATEADD(DAY, 1, DateValue) <= (
                                       SELECT maxDate 
                                         FROM cteDates C2
                                        WHERE C2.id = C1.id
                                     )
)

--SELECT query
SELECT DateValue FROM cteRecursion ORDER BY DateValue OPTION (MAXRECURSION 0)

产生输出:

DateValue
---------
2000-02-01
2000-02-02
2000-02-03
2000-02-04
2000-03-27
2000-03-28
2000-03-29

答案 2 :(得分:0)

一种可能的解决方案是使用数字或理货价格表

.v-menubar > .v-menubar-menuitem:before {
   content: "";
}

结果是

;WITH cteNumbers (N) 
AS(   
    SELECT ROW_NUMBER() OVER(ORDER BY N1.N) 
    FROM (VALUES (1),(1),(1),(1),(1),(1),(1),(1),(1),(1)) N1(N)
    CROSS JOIN (VALUES (1),(1),(1),(1),(1),(1),(1),(1),(1),(1)) N2 (N)
    CROSS JOIN (VALUES (1),(1),(1),(1),(1),(1),(1),(1),(1),(1)) N3 (N)
)
SELECT T1.FromDate
FROM(
    SELECT
        T1.FromDate
    FROM dbo.Table1 T1
    UNION
    SELECT
        DATEADD(DAY, N, T1.FromDate)
    FROM
        dbo.Table1 T1
    CROSS APPLY cteNumbers N
    WHERE N <= DATEDIFF(DAY, T1.FromDate, T1.ToDate)
) T1
WHERE t1.FromDate IN 
(
    SELECT
        T2.FromDate
    FROM dbo.Table2 T2 
    UNION 
    SELECT
        DATEADD(DAY, N, T2.FromDate)
    FROM
        dbo.Table2 T2
    CROSS APPLY cteNumbers N
    WHERE N <= DATEDIFF(DAY, T2.FromDate, T2.ToDate)
) 

“数字/总计”表允许的日期范围最长为1000天。如果您需要更多,请添加另一行,例如FromDate 2000-02-01 00:00:00.000 2000-02-02 00:00:00.000 2000-02-03 00:00:00.000 2000-02-04 00:00:00.000 2000-03-27 00:00:00.000 2000-03-28 00:00:00.000 2000-03-29 00:00:00.000