填写集合中的缺失范围

时间:2016-07-25 14:30:11

标签: sql-server tsql sql-server-2012

这是一个关于提交缺少范围数据的问题。具体来说,我有一个结果集,其中每一行包含一个StartDate和EndDate值。假设我有:

Start     End
1/15      1/20
1/12      3/15

我需要一个生成的查询将以下行添加到数据中:

1/21      2/11

大多数其他相关问题都是关于填补知识集(如日期列表)中的差距。在这种情况下,我只是在寻找丢失数据的开始/结束。

4 个答案:

答案 0 :(得分:2)

假设您打算写1/21而不是2/21,这是一种方法:

with dates as
(
    select '2016-01-15' as dtStart, '2016-01-20' as dtEnd union all
    select '2016-02-12', '2016-03-15' union all
    select '2016-03-21', '2016-04-11'
),

calcs as
(
    select 
        dateadd(day, 1, dtEnd) as rangeStart,
        (select dateadd(day, -1, min(dtStart)) 
            from dates d2 where d2.dtStart > d.dtEnd) as rangeEnd
    from dates d
)

select *
from calcs c
where c.rangeEnd >= c.rangeStart

dates只是三行样本日期。在calcs表格中,rangeStart列是每个dtEnd之后的第二天。 rangeEnd列会使用下一个dtStart并减去一天。最后,最后一行将为null,因为在最后一个dtEnd之后现在缺少范围,所以我忽略了具有空rangeEnd值的行。

编辑:如果您不熟悉我的代码中的with语句,则为CTE。我在这里使用它作为一种快速方法来创建一个包含一些样本数据的表(日期)和一个存储计算的地方(计算)。

Edit2:由于您提到在评论中使用了联接,这是一种方法:

with dates as
(
    select '2016-01-15' as dtStart, '2016-01-20' as dtEnd union all
    select '2016-02-12', '2016-03-15' union all
    select '2016-03-21', '2016-04-11'
),

calcs as
(
    select
        dateadd(day, 1, d1.dtEnd) as rangeStart,
        dateadd(day, -1, min(d2.dtStart)) as rangeEnd
    from dates d1
    join dates d2 on d1.dtEnd < d2.dtStart
    group by d1.dtEnd
)

select *
from calcs
where datediff(day, rangeStart, rangeEnd) >= 0

Edit3:更新了datediff不等式以包含一天的范围

答案 1 :(得分:0)

我建议创建一个日期表。这将使您的查询简单,您可以在其他查​​询中重用。以下是有关创建日期表的文章的链接。希望这会有所帮助。

https://www.mssqltips.com/sqlservertip/4054/creating-a-date-dimension-or-calendar-table-in-sql-server/

答案 2 :(得分:0)

    select * from 
    (select DISTINCT t1.[end] + 1 'start', t2.start - 1 'end'
            from yourtable t1 
            CROSS JOIN 
            yourtable t2
                WHERE 
                    EXISTS(SELECT 0 FROM yourtable t3 WHERE t3.[end] < t2.[start]) 
                AND 
                    NOT EXISTS(SELECT 0 FROM yourtable t4 WHERE t4.start = t1.[end] + 1)
                AND 
                    NOT EXISTS(SELECT 0 FROM yourtable t5 WHERE T5.Start BETWEEN t1.[end] + 1 AND  t2.start - 1 OR T5.[end] BETWEEN t1.[end] + 1 AND t2.start - 1)
                AND
                    t1.[end] + 1 <= t2.start - 1
    UNION
        SELECT start,[end] from yourtable) dq
order by start

答案 3 :(得分:0)

Declare @Table table (Start Date,[End] Date)
Insert into @Table values
('2016-01-15','2016-01-20'),
('2016-02-12','2016-03-15')

;with cteBase as (
    Select *,Gap=DateDiff(DD,Lag([End],1,Start) over (Order By Start),Start) From @Table
)
Select Start=DateAdd(DD,1+Gap*-1,Start),[End]=DateAdd(DD,-1,Start) from cteBase Where Gap<>0

返回

Start       End
2016-01-21  2016-02-11

完整数据集

的可选项
...
Union All
Select Start,[End] from cteBase
Order by Start