简体   繁体   English

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

[英]How to create check constraint with foreign key reference

I am creating a database with these two tables in H2:我在 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
);

So for example there is an instance with capacity of 20.例如,有一个容量为 20 的实例。

Reservation order increments with each reservation to this instance.预留顺序随对该实例的每次预留而增加。

So for example like this:所以例如像这样:

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);

My problem is, that I need to create check constraint that我的问题是,我需要创建检查约束

INSTANCE.CAPACITY >= RESERVATION_ORDER 

so I cannot add another reservation, when there is already 20 of them made to that instance, but I have no idea how to do that.所以我不能添加另一个预订,当已经有 20 个预订时,我不知道该怎么做。 I used SQL only a few times in my life and I have a hard time referencing other tables with a foreign key.我一生中只使用过几次 SQL,我很难用外键引用其他表。

I tried adding something like this when creating the table with no success我在创建表时尝试添加这样的东西但没有成功

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

In SQL, a check constraint can only refer to columns in the same row or user-defined functions.在 SQL 中,检查约束只能引用同一行中的列或用户定义的函数。

You may be able to do what you want by defining a user-defined functions.您可以通过定义用户定义的函数来做您想做的事。 Or you can define a trigger to enforce the constraint.或者您可以定义一个触发器来强制执行约束。

You cannot, however, do so with a simple check constraint.但是,您不能使用简单的检查约束来做到这一点。

The most common way to tackle this problem is the following:解决此问题的最常见方法如下:

  1. Add a column to reservations which is the current number of active instances.reservations添加一列,这是当前活动实例的数量。
  2. Add insert/update/delete triggers to instances and increment/decrement the aforementioned column appropriately.instances添加插入/更新/删除触发器并适当地增加/减少上述列。
  3. Add a check constraint in reservervations that compares the calculated value to the computed count.reservervations中添加一个检查约束,将计算值与计算计数进行比较。

This check constraint will fail.此检查约束将失败。

I prefer this approach over using UDFs in a check constraint because the count is easy to see and verify.我更喜欢这种方法而不是在检查约束中使用 UDF,因为计数很容易查看和验证。

You can define UDF and call that UDF on RESERVATION table.您可以定义 UDF 并在 RESERVATION 表上调用该 UDF。 Something like below :像下面这样:

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); 

You need to add table names or aliases to distinguish INSTANCE_ID column from table RESERVATION from the same column from the table INSTANCE in your check constraint.您需要添加表名或别名,以在检查约束中将INSTANCE_ID列与表RESERVATION与来自表INSTANCE的同一列区分开来。 You also need a foreign key constraint.您还需要一个外键约束。

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)));

I think you should also check that RESERVATION_ORDER is greater than or equal to 1 by replacing RESERVATION_ORDER <= (SELECT … with RESERVATION_ORDER BETWEEN 1 AND (SELECT … .我想你也应该检查RESERVATION_ORDER大于或通过替换等于1 RESERVATION_ORDER <= (SELECT …RESERVATION_ORDER BETWEEN 1 AND (SELECT …

Most likely you also need a UNIQUE constraint to prevent duplicate rows in RESERVATION with the same INSTANCE_ID and RESERVATION_ORDER values.很可能您还需要一个UNIQUE约束来防止RESERVATION具有相同INSTANCE_IDRESERVATION_ORDER值的重复行。

ALTER TABLE RESERVATION ADD UNIQUE(INSTANCE_ID, RESERVATION_ORDER);

Please note that FOREIGN KEY and UNIQUE constraints are always ensured, but CHECK constraints with references to other tables in H2 are validated only when you insert or modify the rows with the constraint.请注意,始终确保FOREIGN KEYUNIQUE约束,但仅当您插入或修改具有约束的行时,才会验证对 H2 中其他表的引用的CHECK约束。 CHECK constraints in H2 aren't re-validated when tables referenced from its subqueries are modified.当修改从其子查询引用的表时,不会重新验证 H2 中的CHECK约束。 So you should either not decrease CAPACITY in existing rows in INSTANCE table, or perform some additional validation when you do that, for example, in a trigger.因此,您不应该减少INSTANCE表中现有行的CAPACITY ,或者在这样做时执行一些额外的验证,例如,在触发器中。

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

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