2017-03-02 1243 views
1

我试图通过开始日期和结束日期约束SQL Server数据库,这样我永远不会对资源进行双重预订(即不会重复预订或重复预订)。日期范围的SQL Server约束

假设我的资源编号,使得该表看起来像 RESOURCEID,起始日期,结束日期,状态

所以可以说我有资源#1。我希望确保2017年1月8日至2017年1月16日的预订无法进行预订,2017年1月10日至2017年1月18日期间对同一资源进行单独预订。

还有一些复杂情况,资源的StartDate可以与资源的EndDate相同。所以1/8/1027到2017年1月16日和2017年1月16日到2017年1月20日是好的(即一个人可以在同一天登记另一个人结账)。

此外,状态字段指示资源的预订是活动还是取消。所以我们可以忽略所有取消的预订。

在保存时,我们已经对代码(存储过程和C#)中的这些重叠或双重预订保留进行了保护,但我们希望通过添加DB保留来添加额外的保护层。

这可能在SQL Server中吗?

由于提前

+0

你可以用触发器做这样的事情,我敢肯定,但我不认为你可以在约束中做你需要的。 – pmbAustin

+1

[日期范围重叠检查约束](http://stackoverflow.com/questions/12035747/date-range-overlapping-check-constraint) – SqlZim

回答

0

可以使用CHECK约束,以确保开始日期是结束日期或之前很轻松地:

CONSTRAINT [CK_Tablename_ValidDates] CHECK ([EndDate] >= [StartDate]) 

约束不会阻止重叠的日期范围帮助。您可以改为使用触发器通过创建一个FOR INSERT,UPDATE触发器回滚事务执行这一点,如果它检测到重复:

CREATE TRIGGER [TR_Tablename_NoOverlappingDates] FOR INSERT, UPDATE AS 
IF EXISTS(SELECT * from inserted INNER JOIN [MyTable] ON blah blah blah ...) BEGIN 
    ROLLBACK TRANSACTION; 
    RAISERROR('hey, no overlapping date ranges here, buddy', 16, 1); 
    RETURN; 
END 

另一种选择是创建查找重复一个索引视图,并把独特的如果存在多于一条记录,将违反该视图的约束条件。这通常是通过一个虚表来实现的,该表有两行笛卡尔连接到一个聚合视图,用于选择重复的id--因此一个具有重复的记录会在视图中返回两个具有相同虚假id值且具有唯一索引的行。

我已经完成了两项工作,我更喜欢触发器方法。

0

从这里回答这个问题:Date range overlapping check constraint

首先,检查,以确保有不存在重叠:

select * 
from dbo.Reservation as r 
where exists (
    select 1 
    from dbo.Reservation i 
    where i.PersonId = r.PersonId 
    and i.ReservationId != r.ReservationId 
    and isnull(i.EndDate,'20990101') > r.StartDate 
    and isnull(r.EndDate,'20990101') > i.StartDate 
); 
go 

如果是全部清除,然后创建你的函数。

有几种不同的编写函数的方法,例如:我们可以跳过StartDateEndDate和使用仅基于ReservationId类似上面的查询的东西,但我会用这个作为例子:

create function dbo.udf_chk_Overlapping_StartDate_EndDate (
    @ResourceId int 
    , @StartDate date 
    , @EndDate date 
) returns bit as 
begin; 
    declare @r bit = 1; 
    if not exists (
    select 1 
    from dbo.Reservation as r 
    where r.ResourceId = @ResourceId 
     and isnull(@EndDate ,'20991231') > r.StartDate 
     and isnull(r.EndDate,'20991231') > @StartDate 
     and r.[Status] = 'Active' 
    group by r.ResourceId 
    having count(*)>1 
) 
    set @r = 0; 
    return @r; 
end; 
go 

添加您的约束:

alter table dbo.Reservation 
    add constraint chk_Overlapping_StartDate_EndDate 
    check (dbo.udf_chk_Overlapping_StartDate_EndDate(ResourceId,StartDate,EndDate)=0); 
go 

末:测试它。