这是我的表
Events
Start : Datetime
End : Datetime
我正在尝试确保新事件不会与之前输入的任何事件重叠。我承认我的SQL知识充其量只是新手。以下是一个让我接近的select语句,但我无法弄清楚如何将其变成约束(我会使用check吗?)
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 :(得分: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 :(得分: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
具有包容性,并在所有数据库上保持一致。
答案 2 :(得分:1)
这可能取决于你正在使用的DBMS,但是这种约束通常需要使用触发器来实现,该触发器执行查询以确定插入/更新是否有效以及如果没有,则回滚交易。 CHECK约束通常只允许您引用“当前行”中的列。
SELECT *
FROM Events E
WHERE E.Start <= NEWEND
AND E.End >= NEWSTART
...将为您提供与之重叠的事件(如果您对'触摸'事件不感兴趣,请更改&lt; =和&gt; =与&lt;和&gt ;.)
答案 3 :(得分: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