Могу ли я добавить CHECK в мой скрипт SQL CREATE TABLE? - PullRequest
0 голосов
/ 06 марта 2020

Я создал эту таблицу для своей базы данных.

CREATE TABLE Reservation
(
Reservation_Name SERIAL UNIQUE PRIMARY KEY,
User VARCHAR(64) DEFAULT 'Member', FOREIGN KEY(User) REFERENCES User(Email)
ON UPDATE CASCADE
ON DELETE SET DEFAULT,
Location INT, FOREIGN KEY(Location) REFERENCES Place(Id_Location)
ON UPDATE CASCADE
ON DELETE NO ACTION,
Start_Date DATE NOT NULL,
Check_In TIME(1) DEFAULT '10:00:00',
End_Date DATE NOT NULL,
Check_Out TIME(1) DEFAULT '18:00:00',
CHECK(Start_Date >= End_Date),
Deleted BOOLEAN DEFAULT FALSE
);

Как вставить чек, который не позволяет добавить резервирование, если уже есть еще одно с той же датой Start_Date и той же датой End_Date, заканчивающейся в том же месте?

Ответы [ 4 ]

1 голос
/ 06 марта 2020

Это работает на sql сервере. У меня нет доступа к чеку против postgres. Вам нужно будет запустить в двух разных пакетах после создания таблицы

Первый

CREATE FUNCTION dbo.HasOverlap (
    @locationId int, @start datetime, @end datetime)
RETURNS VARCHAR(5)
AS
BEGIN
    IF (SELECT count(*) FROM dbo.Reservation WHERE Location = @locationId 
        and (
            @start between Start_Date and End_Date 
            or 
            @end between Start_Date and End_Date
            or
            (@start <=Start_Date and @end>=End_Date )
            )
            ) >1
        return 1
    return 0
END

Второй

Alter Table dbo.Reservation 
with check add Constraint Check_Overlap
check (dbo.HasOverlap(Location, Start_Date, End_Date)=0)
1 голос
/ 06 марта 2020

Вы можете добавить ограничение в таблицу.

Alter Table Reservations Add Constraint unique_reservation Unique(Location,StartDate,EndDate);

Для этого вам понадобится триггер. Посмотрите на приведенный выше код:

CREATE TRIGGER no_overlap
BEFORE INSERT
   ON Reservation FOR EACH ROW
BEGIN
        SET @overlaps = ( SELECT count(*) FROM Reservation WHERE ( ( NEW.Start_Date >= Start_Date AND NEW.Start_Date <= End_Date AND NEW.Location = Location) || ( NEW.End_Date >= Start_Date AND NEW.End_Date <= End_Date AND NEW.Location = Location)));
        IF @overlaps > 0 THEN
          SIGNAL SQLSTATE '45000' SET
          MYSQL_ERRNO = 31000,
          MESSAGE_TEXT = 'Unable to insert an overlapping reservation';
       END IF;

END;

INSERT INTO Reservation (Location,Start_Date,End_Date) VALUES(1,'2020-12-13','2020-12-16');
INSERT INTO Reservation (Location,Start_Date,End_Date) VALUES(1,'2020-12-14','2020-12-17');

Первая вставка будет выполнена успешно, а вторая не удастся с соответствующим сообщением об ошибке, если даты перекрываются:

SQL Error [31000] [45000]: (conn=10) Unable to insert an overlapping reservation

Кстати, я думаю, у вас есть ошибка в определении таблицы. Вместо CHECK (Start_Date> = End_Date), Я думаю, вы имели в виду CHECK (Start_Date <= End_Date), </strong>

Дайте мне знать, если это поможет.

Примечание: я сделал это на MariaDB, но вы можете применить то же самое для любой SQL БД.

1 голос
/ 06 марта 2020

Вы можете использовать исключающее ограничение:

CREATE EXTENSION btree_gist;

ALTER TABLE reservation ADD EXCLUDE USING gist (
   location WITH =,
   daterange(start_date, end_date, '[]') WITH &&
);

Требуется расширение, чтобы можно было создать индекс GiST для столбца integer, а && - это оператор «перекрытия» для диапазона типы.

0 голосов
/ 06 марта 2020

Вам необходимо использовать концепцию составного первичного ключа в MySQL База данных. Его отключение для вставки повторяющихся элементов в указанных c столбцах.

ALTER TABLE table_name ADD CONSTRAINT constraint_name PRIMARY KEY (Start_Date, End_Date, Location)
...