Как создать проверочное ограничение со ссылкой на внешний ключ - PullRequest
0 голосов
/ 01 февраля 2020

Я создаю базу данных с этими двумя таблицами в H2:

CREATE TABLE INSTANCE
( 
     INSTANCE_ID BIGINT AUTO_INCREMENT PRIMARY KEY, 
     DATE DATE, 
     TIME TIME, 
     LOCATION VARCHAR(255), 
     PRICE INT, 
     CAPACITY INT, 
     EVENT_ID INT
);

CREATE TABLE RESERVATION
( 
     RESERVATION_ID BIGINT AUTO_INCREMENT PRIMARY KEY, 
     RESERVATION_ORDER INT NOT NULL, 
     INSTANCE_ID INT NOT NULL, 
     USER_ID INT NOT NULL
);

Так, например, есть экземпляр с емкостью 20.

Шаг заказа резервирования увеличивается с каждым резервированием к этому instance.

Например, вот так:

INSERT INTO RESERVATION VALUES (1,1,1,1);
INSERT INTO RESERVATION VALUES (2,2,1,3);
INSERT INTO RESERVATION VALUES (3,3,1,4);
INSERT INTO RESERVATION VALUES (4,4,1,5);
INSERT INTO RESERVATION VALUES (5,1,3,2);
INSERT INTO RESERVATION VALUES (6,2,3,5);
INSERT INTO RESERVATION VALUES (7,1,6,6);

Моя проблема в том, что мне нужно создать проверочное ограничение, которое

INSTANCE.CAPACITY >= RESERVATION_ORDER 

, поэтому я не могу добавить другое резервирование когда уже 20 из них сделаны для этого экземпляра, но я понятия не имею, как это сделать. Я использовал SQL всего несколько раз в своей жизни, и мне трудно ссылаться на другие таблицы с помощью внешнего ключа.

Я пытался добавить что-то подобное при создании таблицы без успеха

CHECK (RESERVATION_ORDER =< (SELECT CAPACITY FROM INSTANCE WHERE (INSTANCE_ID = INSTANCE_ID)))

Ответы [ 3 ]

0 голосов
/ 02 февраля 2020

Вы можете определить UDF и вызвать его в таблице RESERVATION. Примерно так:

CREATE FUNCTION dbo.CheckInstanceCapacity (@event_id int, @capacity int)
RETURNS int
AS 
BEGIN
  DECLARE @value int
    SELECT @value = CASE WHEN CAPACITY >= @capacity THEN 0 ELSE 1 END
    FROM INSTANCE
    WHERE EVENT_ID = @event_id 
  RETURN @value
END;

ALTER TABLE RESERVATION ADD CONSTRAINT InsCapacity 
CHECK (dbo.CheckInstanceCapacity(EVENT_ID, RESERVATION_ORDER) = 0); 
0 голосов
/ 02 февраля 2020

Вам необходимо добавить имена таблиц или псевдонимы, чтобы отличить guish INSTANCE_ID столбец из таблицы RESERVATION от того же столбца из таблицы INSTANCE в проверочном ограничении. Вам также необходимо ограничение внешнего ключа.

ALTER TABLE RESERVATION ADD
    FOREIGN KEY (INSTANCE_ID) REFERENCES INSTANCE(INSTANCE_ID);

ALTER TABLE RESERVATION ADD
    CHECK(RESERVATION_ORDER <=
        (SELECT CAPACITY FROM INSTANCE I
            WHERE (RESERVATION.INSTANCE_ID = I.INSTANCE_ID)));

Я думаю, вам также следует проверить, что RESERVATION_ORDER больше или равно 1, заменив RESERVATION_ORDER <= (SELECT … на RESERVATION_ORDER BETWEEN 1 AND (SELECT ….

Скорее всего, вам также понадобится ограничение UNIQUE для предотвращения дублирования строк в RESERVATION с одинаковыми значениями INSTANCE_ID и RESERVATION_ORDER.

ALTER TABLE RESERVATION ADD UNIQUE(INSTANCE_ID, RESERVATION_ORDER);

Обратите внимание, что ограничения FOREIGN KEY и UNIQUE всегда обеспечиваются, но CHECK ограничения со ссылками на другие таблицы в H2 проверяются только при вставке или изменении строк с ограничением. Ограничения CHECK в H2 не проходят повторную проверку при изменении таблиц, на которые ссылаются его подзапросы. Поэтому вам не следует уменьшать CAPACITY в существующих строках таблицы INSTANCE или выполнять дополнительную проверку, когда вы делаете это, например, в триггере.

0 голосов
/ 01 февраля 2020

В SQL проверочное ограничение может ссылаться только на столбцы в той же строке или пользовательские функции.

Вы можете делать то, что хотите, определив пользовательские функции. Или вы можете определить триггер для принудительного применения ограничения.

Однако вы не можете сделать это с помощью простого проверочного ограничения.

Наиболее распространенный способ решения этой проблемы заключается в следующем:

  1. Добавьте столбец к reservations, который является текущим числом активных экземпляров.
  2. Добавьте триггеры вставки / обновления / удаления к instances и соответственно увеличьте / уменьшите вышеупомянутый столбец.
  3. Добавьте проверочное ограничение в reservervations, которое сравнивает вычисленное значение с вычисленным счетчиком.

Это проверочное ограничение не будет выполнено.

Я предпочитаю этот подход по сравнению с использованием UDF в проверочном ограничении, потому что их легко увидеть и проверить.

...