触发重叠的日期时间

时间:2018-12-25 16:16:56

标签: sql-server tsql triggers

我有一个代码表:

CREATE TABLE Event
(
    EventId INT IDENTITY(1,1) CONSTRAINT pk_Event PRIMARY KEY,
    ConferenceId INT NOT NULL,
    FOREIGN KEY (ConferenceId) REFERENCES Conference(ConferenceId),
    RoomId INT,
    FOREIGN KEY (RoomId) REFERENCES Room(RoomId),
    BeginDate DATETIME NOT NULL,
    EndDate DATETIME NOT NULL,
    Title VARCHAR(200) NOT NULL,
    Description VARCHAR(2000) NOT NULL,
    CONSTRAINT date_ck CHECK (DATEDIFF(MINUTE, beginDate, endDate) > 0 
                              AND DATEDIFF(HOUR, beginDate, endDate) <= 5)
);

现在,我正在尝试创建一个触发器,以防止添加两个时间重叠的事件,现在两个事件可以同时发生。我有这样的东西:

CREATE TRIGGER CheckTwoEventsForOverlapingTime
ON [dbo].Event  
AFTER INSERT, UPDATE 
AS 
    IF EXISTS(SELECT begindate, enddate
              FROM Event e
              WHERE e.conferenceId in (SELECT ConferenceId FROM inserted) 
                AND ((SELECT BeginDate FROM inserted) > BeginDate  
                     AND (SELECT BeginDate FROM inserted) <= EndDate) OR
                    ((SELECT EndDate FROM inserted) >= BeginDate  
                     AND (SELECT EndDate FROM inserted) < EndDate) OR
                    ((SELECT BeginDate FROM inserted) < BeginDate 
                     AND (SELECT EndDate FROM inserted) > EndDate)) 
    BEGIN 
        RAISERROR('No two events can take place at the same time.', 16, 1)
        ROLLBACK 
    END
GO

可悲的是,这不想起作用。如果事件A从10AM开始持续到1PM,当我尝试添加事件B,该事件B从10AM开始但持续到2PM时,它不会抛出错误。我不知道怎么了。

2 个答案:

答案 0 :(得分:2)

嗯。我认为逻辑是:

if exists (select 1
           from event e join
                inserted i
                on i.conferenceId = e.conferenceId and
                   i.begindate <= e.enddate and
                   i.enddate >= e.begindate
          )
begin 
    raiseerror('No two events can take place at the same time.', 16, 1);
    rollback; 
end;

逻辑是,当一个事件在第二个结束之前(在或结束时)开始,而在第二个结束之后的第一个结束(在或结束时)时,两个事件重叠。

rollback是多余的-代码永远不会在那里。

<= / <>= / >上的确切逻辑取决于您如何定义重叠。如果允许一个事件恰好在第二个事件开始时才结束,那么请改用< / >

答案 1 :(得分:2)

您必须检查两组。首先,inserted集中不得有任何重叠的事件。然后,inserted与未更改但仍保留的集合(即表中已存在但deleted中没有的集合)之间不得有任何重叠事件。

...
IF EXISTS (SELECT *
                  FROM inserted i1
                       INNER JOIN inserted i2
                                  ON i1.conferenceid = i2.conferenceid
                                     AND i1.eventid <> i2.eventid
                                     AND i1.enddate > i2.begindate
                                     AND i1.begindate < i2.enddate)
   OR EXISTS (SELECT *
                     FROM (SELECT *
                                  FROM event e1
                                  WHERE NOT EXISTS (SELECT *
                                                           FROM deleted d1
                                                           WHERE d1.eventid = e1.eventid) e2
                          INNER JOIN inserted i2
                                     ON e2.conferenceid = i2.conferenceid
                                        AND e2.eventid <> i2.eventid
                                        AND e2.enddate > i2.begindate
                                        AND e2.begindate < i2.enddate))
BEGIN
  THROW 50000, 'No two events can take place at the same time.', 1;
END;
...

我还根据manual的说明将RAISERROR更改为THROW

  

新应用程序应改用THROW