使用 SQL 查找冲突的日期间隔 [英] Find conflicted date intervals using SQL

查看:29
本文介绍了使用 SQL 查找冲突的日期间隔的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

ItemId StartDate EndDate1 NULL 2011-01-152 2011-01-16 2011-01-253 2011-01-26 无

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

ItemId StartDate EndDate1 NULL 2011-01-172 2011-01-16 2011-01-253 2011-01-26 无

NULL 在这里表示无穷大.

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

【第二个任务】

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

<块引用>

ItemId IntervalId StartDate EndDate1 1 NULL 2011-01-152 1 2011-01-16 2011-01-253 1 2011-01-26 无4 2 NULL 2011-01-175 2 2011-01-16 2011-01-256 2 2011-01-26 无

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

还有.是否可以在表中添加约束以避免此类无效记录?

[最终解决方案]

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

创建函数 [dbo].[fnIntervalConflict](@intervalId INT,@originalItemId INT,@startDate 日期时间,@endDate 日期时间)返回位作为开始SET @startDate = ISNULL(@startDate,'1/1/1753 12:00:00 AM')SET @endDate = ISNULL(@endDate,'12/31/9999 11:59:59 PM')声明@conflict BIT = 0选择顶部 1 @conflict = 1来自项目哪里IntervalId = @intervalIdAND ItemId <>@originalItemId和 ((ISNULL(StartDate,'1/1/1753 12:00:00 AM') >= @startDateAND ISNULL(StartDate,'1/1/1753 12:00:00 AM') <= @endDate)或 (ISNULL(EndDate,'12/31/9999 11:59:59 PM') >= @startDateAND ISNULL(EndDate,'12/31/9999 11:59:59 PM') <= @endDate))返回@冲突结尾

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

ALTER TABLE dbo.Items 添加约束CK_Items_Dates CHECK (StartDate IS NULL OR EndDate IS NULL OR StartDate <= EndDate)走

ALTER TABLE dbo.Items 添加约束CK_Items_ValidInterval 检查 (([dbo].[fnIntervalConflict]([IntervalId], ItemId,[StartDate],[EndDate])=(0)))走

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

解决方案

declare @T table (ItemId int, IntervalID int, StartDate datetime, EndDate datetime)插入@T选择 1, 1, NULL, '2011-01-15' union all选择 2, 1, '2011-01-16', '2011-01-25' union allselect 3, 1, '2011-01-26', NULL union all选择 4, 2, NULL, '2011-01-17' union all选择 5, 2, '2011-01-16', '2011-01-25' union all选择 6, 2, '2011-01-26', NULL选择 T1.*从@T 作为 T1内连接 @T 作为 T2在合并(T1.StartDate,'1753-01-01')<合并(T2.EndDate,'9999-12-31')和合并(T1.EndDate,'9999-12-31')>合并(T2.StartDate,'1753-01-01')和T1.IntervalID = T2.IntervalID 和T1.ItemId <>T2.ItemId

结果:

ItemId IntervalID StartDate EndDate----------- ----------- --------------- -----------------------5 2 2011-01-16 00:00:00.000 2011-01-25 00:00:00.0004 2 NULL 2011-01-17 00:00:00.000

Suppose I have following table in Sql Server 2008:

ItemId StartDate   EndDate
1      NULL        2011-01-15
2      2011-01-16  2011-01-25
3      2011-01-26  NULL

As you can see, this table has StartDate and EndDate columns. I want to validate data in these columns. Intervals cannot conflict with each other. So, the table above is valid, but the next table is invalid, becase first row has End Date greater than StartDate in the second row.

ItemId StartDate   EndDate
1      NULL        2011-01-17
2      2011-01-16  2011-01-25
3      2011-01-26  NULL

NULL means infinity here.

Could you help me to write a script for data validation?

[The second task]

Thanks for the answers. I have a complication. Let's assume, I have such table:

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

Here I want to validate intervals within a groups of IntervalId, but not within the whole table. So, Interval 1 will be valid, but Interval 2 will be invalid.

And also. Is it possible to add a constraint to the table in order to avoid such invalid records?

[Final Solution]

I created function to check if interval is conflicted:

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

And then I added 2 constraints to my table:

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

GO

and

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

GO

I know, the second constraint slows insert and update operations, but it is not very important for my application. And also, now I can call function fnIntervalConflict from my application code before inserts and updates of data in the table.

解决方案

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

Result:

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

这篇关于使用 SQL 查找冲突的日期间隔的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆