SQL Server / Transact SQL:在预留中查找时间冲突

时间:2018-01-22 22:08:10

标签: sql-server tsql sql-server-2016 database-trigger

我正在开发一个用于房间预订的数据库。我希望有一个触发器来检查预订是否存在时间冲突。

第一种情况是定义的时间(在“设置”表中定义),无法进行预订。 ('开始'时间不得在禁止范围内)这已经按预期工作:

CREATE TABLE dbo.einstellungen --setings
(
     einst_id varchar(30) CONSTRAINT pk_einstellungen PRIMARY KEY, --setting-id
     beschreibung varchar(300) NOT NULL, --description
     wert_char varchar(300), --wert = value
     wert_int int,
     wert_float float,
     wert_datetime datetime,
     wert_time time,

     CONSTRAINT ck_einstellungen_wert 
         CHECK (wert_char IS NOT NULL
                OR wert_datetime IS NOT NULL
                OR wert_int IS NOT NULL
                OR wert_time IS NOT NULL
                OR wert_float IS NOT NULL)
);

INSERT INTO dbo.einstellungen (einst_id, beschreibung, wert_time)
VALUES ('keine_lv_startzeit', 'Ab dieser Uhrzeit können Räume nicht mehr reserviert werden', '22:00:00') --rooms can't be reserved starting from this time
      ,('keine_lv_endzeit', 'Ab dieser Uhrzeit können Räume reserviert werden', '07:00:00'); --...and ending at this time
GO


CREATE TRIGGER dbo.reservierung_iu --reservations
ON dbo.reservierung --reservations
FOR insert, update
AS
BEGIN;
    SET NOCOUNT ON;

    DECLARE @sperreanfang TIME(0) = (SELECT wert_time  
                                     FROM dbo.einstellungen
                                     WHERE einst_id = 'keine_lv_startzeit'); --begin of "lock"
    DECLARE @sperreende TIME(0) = (SELECT wert_time  
                                   FROM dbo.einstellungen 
                                   WHERE einst_id = 'keine_lv_endzeit'); --end of "lock"

    -- Zeitcheck dbo.einstellungen
    IF (SELECT COUNT(*) FROM inserted WHERE cast(beginn as time) > @sperreanfang OR cast(beginn as time) < @sperreende) > 0 --Is the Begin time of the new reservation within the "lock time"?
    BEGIN;
        ROLLBACK; --If yes - abort

        DECLARE @errormessage varchar(100) = ('Raumreservierungen sind nur für Zeiten von ' + CAST(@sperreende as varchar(10)) + ' bis ' + cast(@sperreanfang as varchar(10)) + ' möglich.');
        THROW 50000, @errormessage , 1;
    END;
    --some more code which doesn't work as intended
END;

然而,下一部分应该检查房间是否在相同的时间跨度内没有预订两次,以及如果教师为不同的房间预订两次也不起作用 - &gt;即使预订表完全为空,触发器也会始终抛出错误。这些是相关表格和触发器的其余部分:

CREATE TABLE dbo.reservierung
(reservierungs_ID int IDENTITY CONSTRAINT pk_reservierungs_ID PRIMARY KEY, --reservation ID
beginn datetime not null, --begin time of reservation
ende datetime not null, --end time of reservation
lehrender int NOT NULL CONSTRAINT fk_reservierung_lehrender FOREIGN KEY REFERENCES dbo.personal(personalnummer), --teacher ID
lehrveranstaltungen varchar(12) NOT NULL CONSTRAINT fk_reservierung_lehrveranstaltungen FOREIGN KEY REFERENCES dbo.lehrveranstaltungen(Lv_Kürzel), --reference to course (not really relevant here)
raum varchar(20) NOT NULL CONSTRAINT fk_reservierung_räume FOREIGN KEY REFERENCES dbo.räume(raum_ID), -- reference to room
constraint chk_ende check (ende > beginn)
); --reservation can't end before it begins
--INSERT INTO dbo.reservierung(beginn, ende, lehrender, lehrveranstaltungen, raum)
--VALUES('20171201 16:00:00', '20171201 17:00:00', 1, 'CBSGL', 'G.AP147.318'); (example reservation - 1 refers to the teacher, 'CBSGL' is the name of the course)

-

ELSE IF (SELECT COUNT(*) FROM inserted i INNER JOIN dbo.reservierung re ON i.reservierungs_ID = re.reservierungs_ID INNER JOIN dbo.räume ra ON ra.raum_ID = re.raum -- New reservation(s), old reservation, rooms
    WHERE ra.raum_ID = i.raum AND ((re.beginn > i.beginn AND re.beginn < i.ende) OR (re.ende > i.beginn AND re.ende < i.ende))) > 0 --are there existing reservations which would overlap with the new one?
    BEGIN;
        ROLLBACK; -- if yes, abort
        THROW 50001, 'Der Raum ist zu dieser Zeit bereits belegt!', 1;
    END;
ELSE IF (SELECT COUNT(*) FROM inserted i INNER JOIN dbo.reservierung re ON i.reservierungs_ID = re.reservierungs_ID
WHERE re.lehrender = i.lehrender AND ((cast(re.beginn as time) > cast(DATEADD(minute, -15, i.beginn) as time) AND --is there an existing reservation which begins after the new reservation begins....
                                            cast(re.beginn as time) < cast(DATEADD(minute, 15, i.ende) as time)) -- ... and before it ends (including a 15 minute buffer)
                                        OR (cast(re.ende as time) > cast(DATEADD(minute, -15, i.beginn) as time) AND --or is there an existing reservation which ends after the new one begins...
                                            cast(re.ende as time) < cast(DATEADD(minute, 15, i.ende) as time)))) > 0 --- and before it ends
BEGIN;
    ROLLBACK;
    THROW 50004, 'Der Lehrende ist zu dieser Zeit nicht verfügbar (Es müssen immer 15 Minuten zwischen Lehrveranstaltungen liegen!', 1;
END;

我尝试了几种不起作用的方法,其中一些我在stackoverflow上发现,我认为非常接近正确的解决方案,这就是为什么我决定在这里创建一个帐户。 我真的很感激任何帮助我更接近解决方案的帮助。

0 个答案:

没有答案