![](/img/trans.png)
[英]Is it not possible to have a check constraint reference a column that also has a foreign key?
[英]How to create check constraint with foreign key reference
我在 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 的实例。
预留顺序随对该实例的每次预留而增加。
所以例如像这样:
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)))
在 SQL 中,检查约束只能引用同一行中的列或用户定义的函数。
您可以通过定义用户定义的函数来做您想做的事。 或者您可以定义一个触发器来强制执行约束。
但是,您不能使用简单的检查约束来做到这一点。
解决此问题的最常见方法如下:
reservations
添加一列,这是当前活动实例的数量。instances
添加插入/更新/删除触发器并适当地增加/减少上述列。reservervations
中添加一个检查约束,将计算值与计算计数进行比较。此检查约束将失败。
我更喜欢这种方法而不是在检查约束中使用 UDF,因为计数很容易查看和验证。
您可以定义 UDF 并在 RESERVATION 表上调用该 UDF。 像下面这样:
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);
您需要添加表名或别名,以在检查约束中将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
约束,但仅当您插入或修改具有约束的行时,才会验证对 H2 中其他表的引用的CHECK
约束。 当修改从其子查询引用的表时,不会重新验证 H2 中的CHECK
约束。 因此,您不应该减少INSTANCE
表中现有行的CAPACITY
,或者在这样做时执行一些额外的验证,例如,在触发器中。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.