2010-08-17 38 views
1

之间这是我的表SQL约束多个值

Events 
Start : Datetime 
End : Datetime 

我想确保一个新的事件不重叠任何先前输入的事件。我承认我的SQL知识是最好的新手。以下是让我接近一个SELECT语句,但我无法弄清楚如何把它变成一个约束(我会用检查?)

SELECT e.* 
FROM Events 
WHERE Start BETWEEN e.START and e.END 
OR End BETWEEN new.START and new.END 
OR (Start < e.Start and End > e.End) 

我想像如果类似的东西返回任何东西有重叠。

编辑:更新了“sql”语句以涵盖我的逻辑故障。它最有可能仍然很差。我非常感谢所有的帮助!

+0

为了什么数据库? CHECK约束存在于MySQL上,但未被强制执行。 – 2010-08-17 19:45:25

+0

Microsoft SQL Server。版本9.00。 – MushinNoShin 2010-08-17 19:50:10

回答

4

这实际上必须进入代码或触发器。约束仅在行级操作

CREATE TRIGGER TRG_Events_INSERT On EventsFOR INSERT 
AS 
IF EXISTS (SELECT * 
    FROM Events E 
     JOIN 
     INSERTED INS 
     ON 
      (E.Start Between INS.START and INS.END) 
      OR 
      (E.End Between INS.START and INS.END) 
      OR 
      (E.Start < INS.START and E.End > INS.END) 

    WHERE 
     E.Key <> INS.Key --already inserted at this point 

BEGIN 
    ROLLBACK TRAN 
    --etc 
END 
GO 
1

这可能取决于您正在使用的DBMS,但通常需要使用触发器执行此约束,该触发器执行查询以确定插入/更新是否有效并回退事务如果不。 CHECK约束通常只允许您引用“当前行”中的列。

SELECT * 
FROM Events E 
WHERE E.Start <= NEWEND 
AND E.End >= NEWSTART 

...会得到你所重叠的事件(改变< =和> =与<和>如果你不感兴趣的“接触”事件)。

+0

什么都不起作用,甚至连我的创新'重叠'检查都没有投票。啧! – 2010-08-17 20:02:15

+0

+1:用于捕捉日期重叠。为了全部触发代码,我投了GBN的答案。 – 2010-08-17 20:03:42

3

您提供的SQL语法上不正确的 - 使用:

SELECT e.* 
    FROM EVENTS e 
WHERE start BETWEEN e.START and e.END 
    OR end BETWEEN e.START and e.END 
    OR (start < e.START AND end > e.END) 

BETWEEN是包容性的,并且对所有数据库一贯支持。

+1

这不包括事件在现有事件之前开始并在该事件完成之后结束的情况。 – 2010-08-17 19:50:53

+0

@ Will A:当然可以:p – 2010-08-17 19:58:47

+0

厚颜无耻的猴子!好的,那就是+1。诚然,OP没有提及这构成重叠,但我们知道它确实存在。 :) – 2010-08-17 19:59:38

0

你可以做的是在连接中将表与自己进行比较。下面是如何做到这一点的例子。我注释了一些行。取消他们的评论,看看它处理不同情况的进展情况。

编辑:如果你需要这个作为表本身的约束,你应该去触发器。

edit2:对于SQL 2005,用单独的插入语句替换插入语法。

祝你好运,

GJ

declare @event table (
    Id int, 
    Start DateTime, 
    Stop DateTime 
) 

insert @event (Id, Start, Stop) 
values (1, '2010-08-01', '2010-08-02') 
    ,(2, '2010-08-04', '2010-08-06') 
    ,(3, '2010-08-05', '2010-08-08') -- start fals within event 2 
    --,(4, '2010-01-01', '2010-12-31') -- overlaps with all of them 
    --,(5, '2010-08-01', '2010-08-02')  -- equal to event 1 

select * 
from @event e1 
     inner join @event e2 
      on e1.Id != e2.Id   -- do not compare to itself 
      and e2.Start >= e1.Start -- events that have a start date 
      and e2.Start <= e1.Stop