使用SQL查找冲突的日期间隔

Ego*_*4eg 5 sql t-sql sql-server

假设我在Sql Server 2008中有以下表:

ItemId StartDate   EndDate
1      NULL        2011-01-15
2      2011-01-16  2011-01-25
3      2011-01-26  NULL
Run Code Online (Sandbox Code Playgroud)

如您所见,此表具有StartDate和EndDate列.我想验证这些列中的数据.间隔不能相互冲突.因此,上表是有效的,但下一个表无效,因为第一行的结束日期大于第二行中的StartDate.

ItemId StartDate   EndDate
1      NULL        2011-01-17
2      2011-01-16  2011-01-25
3      2011-01-26  NULL
Run Code Online (Sandbox Code Playgroud)

NULL 在这里意味着无限.

你能帮我写一个数据验证脚本吗?

[第二项任务]

谢谢你的回答.我有一个并发症.我们假设,我有这样的表:

ItemId  IntervalId StartDate   EndDate
1       1          NULL        2011-01-15
2       1          2011-01-16  2011-01-25
3       1          2011-01-26  NULL
4       2          NULL        2011-01-17
5       2          2011-01-16  2011-01-25
6       2          2011-01-26  NULL
Run Code Online (Sandbox Code Playgroud)

在这里,我想验证一组内的间隔IntervalId,但不是整个表内的间隔.因此,Interval 1将有效,但Interval 2将无效.

并且.是否可以向表中添加约束以避免此类无效记录?

[最终解决方案]

我创建了函数来检查间隔是否冲突:

CREATE FUNCTION [dbo].[fnIntervalConflict]
(
    @intervalId INT,
    @originalItemId INT,
    @startDate DATETIME,
    @endDate DATETIME
)
RETURNS BIT
AS
BEGIN

    SET @startDate = ISNULL(@startDate,'1/1/1753 12:00:00 AM')
    SET @endDate = ISNULL(@endDate,'12/31/9999 11:59:59 PM')

    DECLARE @conflict BIT = 0

    SELECT TOP 1 @conflict = 1
    FROM Items
    WHERE IntervalId = @intervalId
    AND ItemId <> @originalItemId
    AND (
    (ISNULL(StartDate,'1/1/1753 12:00:00 AM') >= @startDate 
     AND ISNULL(StartDate,'1/1/1753 12:00:00 AM') <= @endDate)
     OR (ISNULL(EndDate,'12/31/9999 11:59:59 PM') >= @startDate 
     AND ISNULL(EndDate,'12/31/9999 11:59:59 PM') <= @endDate)
    )

    RETURN @conflict
END
Run Code Online (Sandbox Code Playgroud)

然后我在表格中添加了2个约束:

ALTER TABLE dbo.Items ADD CONSTRAINT
    CK_Items_Dates CHECK (StartDate IS NULL OR EndDate IS NULL OR StartDate <= EndDate)

GO
Run Code Online (Sandbox Code Playgroud)

ALTER TABLE dbo.Items ADD CONSTRAINT
    CK_Items_ValidInterval CHECK (([dbo].[fnIntervalConflict]([IntervalId], ItemId,[StartDate],[EndDate])=(0)))

GO
Run Code Online (Sandbox Code Playgroud)

我知道,第二个约束会减慢插入和更新操作,但对我的应用程序来说并不是很重要.而且,现在我可以fnIntervalConflict在表中插入和更新数据之前从我的应用程序代码调用函数.

Mik*_*son 2

declare @T table (ItemId int, IntervalID int, StartDate datetime,   EndDate datetime)

insert into @T
select 1, 1,  NULL,        '2011-01-15' union all
select 2, 1, '2011-01-16', '2011-01-25' union all
select 3, 1, '2011-01-26',  NULL        union all
select 4, 2,  NULL,        '2011-01-17' union all
select 5, 2, '2011-01-16', '2011-01-25' union all
select 6, 2, '2011-01-26',  NULL

select T1.*
from @T as T1
  inner join @T as T2
    on coalesce(T1.StartDate, '1753-01-01') < coalesce(T2.EndDate, '9999-12-31') and
       coalesce(T1.EndDate, '9999-12-31') > coalesce(T2.StartDate, '1753-01-01') and
       T1.IntervalID = T2.IntervalID and
       T1.ItemId <> T2.ItemId
Run Code Online (Sandbox Code Playgroud)

结果:

ItemId      IntervalID  StartDate               EndDate
----------- ----------- ----------------------- -----------------------
5           2           2011-01-16 00:00:00.000 2011-01-25 00:00:00.000
4           2           NULL                    2011-01-17 00:00:00.000
Run Code Online (Sandbox Code Playgroud)