如何防止SQL中的日期重叠?

时间:2012-03-06 10:04:31

标签: sql tsql sql-server-2008-r2

我有一个雇佣表的表结构:

hireId int primary key
carId int not null foreign key
onHireDate datetime not null
offHireDate datetime not null

我正在尝试对多用户系统进行编程,该系统不允许汽车重叠时间段和非工作时段。我需要能够以非连续顺序添加招聘。还需要允许编辑招聘。

任何限制表格或使用触发器等以防止重叠的方法?我正在使用实体框架,所以我想要正常插入表,然后如果失败则抛出一些可捕获的异常等。

3 个答案:

答案 0 :(得分:3)

CREATE TRIGGER tri_check_date_overlap ON your_table
INSTEAD OF INSERT 
AS
BEGIN
    IF @@ROWCOUNT = 0
       RETURN

    -- check for overlaps in table 'INSERTED'
    IF EXISTS(
        SELECT hireId FROM your_table WHERE 
             (INSERTED.onHireDate BETWEEN onHireDate AND offHireDate) OR
             (INSERTED.offHireDate BETWEEN onHireDate AND offHireDate) 
    )
        BEGIN   
           -- exception? or do nothing?
        END
    ELSE
        BEGIN
        END
END
GO

答案 1 :(得分:3)

考虑这个问题:

SELECT *
FROM Hire AS H1, Hire AS H2
WHERE H1.carId = H2.carId
AND H1.hireId < H2.hireId 
AND 
   CASE 
   WHEN H1.onHireDate > H2.onHireDate THEN H1.onHireDate 
   ELSE H2.onHireDate END
   <
   CASE 
   WHEN H1.offHireDate > H2.offHireDate THEN H2.offHireDate 
   ELSE H1.offHireDate END

如果所有行都符合您的业务规则,则此查询将为空集(假设为closed-open representation of periods,即结束日期是该时段内未考虑的最早时间粒度。)

由于SQL Server does not support subqueries within CHECK constraints,将相同的逻辑放在触发器中(但不是INSTEAD OF触发器,除非您可以为解决重叠提供逻辑)。


使用Fowler的替代查询:

SELECT *
  FROM Hire AS H1, Hire AS H2
 WHERE H1.carId = H2.carId
       AND H1.hireId < H2.hireId 
       AND H1.onHireDate < H2.offHireDate 
       AND H2.onHireDate < H1.offHireDate;

答案 2 :(得分:0)

我现在正在使用域驱动设计技术。这使我不必担心数据库触发器等,并将所有逻辑保留在.Net代码中。答案在这里,以便人们可以看到替代方案。

我将句点集合的父级视为aggregate root,并且根目录有时间戳。聚合根是事务,分发和并发的一致性边界(参见Evans - what I've learned since the blue book)。这用于检查上次向数据库确认任何更改的时间。

然后,我有方法将雇用期间添加到父级。我在将运动添加到聚合根时测试重叠。例如AddHire(start,end) - 将验证这在内存域对象中不会产生重叠。

AS没有重叠我保存更改(通过我的存储库),并检查数据库时间戳仍然与进程开始时相同。假设时间戳与检索实体时的时间戳相同,则更改将保持不变,数据库将更新时间戳。

如果其他人尝试在处理聚合根时保存更改,那么我将首先提交或者他们将提交。如果我先提交,则时间戳将不匹配,重叠检查将重新运行,以确保它们在中间时间内没有创建重叠。