繁体   English   中英

如何使用外键引用创建检查约束

[英]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 中,检查约束只能引用同一行中的列或用户定义的函数。

您可以通过定义用户定义的函数来做您想做的事。 或者您可以定义一个触发器来强制执行约束。

但是,您不能使用简单的检查约束来做到这一点。

解决此问题的最常见方法如下:

  1. reservations添加一列,这是当前活动实例的数量。
  2. instances添加插入/更新/删除触发器并适当地增加/减少上述列。
  3. 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_IDRESERVATION_ORDER值的重复行。

ALTER TABLE RESERVATION ADD UNIQUE(INSTANCE_ID, RESERVATION_ORDER);

请注意,始终确保FOREIGN KEYUNIQUE约束,但仅当您插入或修改具有约束的行时,才会验证对 H2 中其他表的引用的CHECK约束。 当修改从其子查询引用的表时,不会重新验证 H2 中的CHECK约束。 因此,您不应该减少INSTANCE表中现有行的CAPACITY ,或者在这样做时执行一些额外的验证,例如,在触发器中。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM