不包括日期范围的SQL查询

时间:2015-03-25 13:59:11

标签: sql sql-server-2008 date range

我有一段时间,我想排除日期范围

例如

id   startDate  endDate
316  2015-02-01     NULL

排除表

id    ExclusionStartDate ExclusionEndDate

316   2015-02-15         2015-02-18     
316   2015-03-10         2015-03-15 
316   2015-04-01         2015-04-30    

我搜索结果:

Id       startDate            endDate

316   2015-02-01              2015-02-14 
316   2015-02-19              2015-03-09 
316   2015-03-16              2015-03-31 
316   2015-05-01              null

我可以使用递归查询吗?

2 个答案:

答案 0 :(得分:1)

尝试:

DECLARE @i TABLE(id int, sd DATE, ed DATE)
DECLARE @e TABLE(id int, sd DATE, ed DATE)

INSERT INTO @i VALUES
(316, '20150201', NULL),
(317, '20150202', NULL)
INSERT INTO @e VALUES
(316, '20150215', '20150218'),
(316, '20150310', '20150315'),
(316, '20150401', '20150430'),
(317, '20150405', '20150530')


;WITH cte AS
(
    SELECT id, sd, ROW_NUMBER() OVER(PARTITION BY id ORDER BY ord, sd) AS rn FROM 
    (
      SELECT id, sd, 0 AS ord FROM @i
      UNION ALL
      SELECT id, DATEADD(dd, -1, sd), 1 AS ord FROM @e
      UNION ALL
      SELECT id, DATEADD(dd, 1, ed), 1 AS ord FROM @e
      UNION ALL
      SELECT id, ed, 2 AS ord FROM @i
    ) t
)

SELECT c1.id, c1.sd, c2.sd AS ed FROM cte c1
JOIN cte c2 ON c1.rn + 1 = c2.rn AND c1.id = c2.id
WHERE c2.rn % 2 = 0
ORDER BY c2.id, c2.rn

输出:

id  sd          ed
316 2015-02-01  2015-02-14
316 2015-02-19  2015-03-09
316 2015-03-16  2015-03-31
316 2015-05-01  NULL
317 2015-02-02  2015-04-04
317 2015-05-31  NULL

答案 1 :(得分:0)

您不需要递归查询。您只需列出所有日期,以及它们是开始日期还是结束日期,然后重新构建期间。如果您假设排除期间不重叠(如您的示例所示)

select t.*
from (select id, dte as startDate,
             lead(dte) over (partition by id order by dte) as endDate,
             isStart
      from ((select id, startDate as dte, 1 as isStart from example) union all
            (select id, endDate as dte, 0 as isStart from example) union all
            (select id, exclustionstartDate - interval 1 day as dte, 1 as isStart from exclusion) union all
            (select id, exclustionendDate + interval 1 day as dte, 0 as IsStart from exclusion)
           ) t
     ) t
where isStart = 1;

将日期添加到日期的语法取决于数据库。这仅使用+ interval 1 day,但为数据库使用适当的逻辑。