[英]REFERENCES two different columns in two different tables
在 Postgresql 数据库中,我们有一个如下表:
=# SELECT * FROM toy_cars;
serial_no | name
------------+---------------
199ER276FN | Snow Doctor
8BE0F79A3R | Flatbed Truck
D76185CE8G | Sand Speeder
=# SELECT * FROM toy_trains;
serial_no | name
-----------------+-------------
BMXH5R4T8K7KELD | Howler T140
B1Q1JJDQW9LQN0G | Quakester
8HO9240TO6RNNQ9 | Medusa 90
=# SELECT * FROM items_for_sale;
serial_no | in_stock
-----------------+---------------
199ER276FN | t
BMXH5R4T8K7KELD | t
B1Q1JJDQW9LQN0G | f
8BE0F79A3R | f
8HO9240TO6RNNQ9 | t
D76185CE8G | f
笔记:
每个serial_no
列都是该表的主键,而in_stock
是 boolean。
toy_cars
表中的serial_no
有一个正则表达式CHECK
限制,只允许 10 个字符。
toy_trains
表中的serial_no
有一个正则表达式CHECK
限制,只允许 15 个字符。
items_for_sale
表中的serial_no
是玩具汽车或火车的序列号,并且具有正则表达式CHECK
限制,仅允许 10 或 15 个字符。
所有serial_no
列都有UNIQUE
约束。
我们想在items_for_sale
表中为serial_no
添加一个REFERENCES
检查,以确保输入的序列号存在于toy_cars
表或toy_trains
表中。
所以,如果我要尝试INSERT INTO items_for_sale VALUES('KYVGK0DBYXPMWW8','f');
这将失败,因为该序列不存在于toy_cars
或toy_trains
中。
如何才能做到这一点? 我们更喜欢使用一张表(就像它现在的结构一样)。
这里的问题是您想检查两个(其他)表中是否存在键,并且您无法在单个列上使用外键约束来强制执行该操作。 Postgres 允许您为自定义检查创建CHECK
表达式,但正如手册所述:
PostgreSQL 不支持引用表数据的 CHECK 约束,而不是正在检查的新行或更新行。 (...) 如果可能,请使用 UNIQUE、EXCLUDE 或 FOREIGN KEY 约束来表示跨行和跨表限制。
如果您想要的是在插入行时对其他行进行一次性检查,而不是持续保持一致性保证,则可以使用自定义触发器来实现它。
有关不同的解决方案,请参阅这个非常相关的问题。
某些数据库(MS SQL 服务器)允许您在CHECK
表达式中使用 function 。 那将是最佳的,但 Postgres 不允许这种语法。
对于 PostgreSQL,您需要创建一个TRIGGER
,该触发器将在将某些内容插入items_for_sale
时执行。 另一方面,这确实允许函数或跨表检查。
它看起来像这样:
CREATE TRIGGER check_serial_present
BEFORE INSERT ON items_for_sale
FOR EACH ROW
EXECUTE FUNCTION assert_presence_of_serial(); -- implement this function
另一个链接的问题还提到了一种非常优雅的方式来实现这一点而无需触发器:
没有触发器的干净解决方案:添加冗余列并将它们包含在 FOREIGN KEY 约束中
我非常喜欢这个,因为它在概念上非常简单且易于掌握。 我认为它只涉及以下步骤:
ALTER TABLE
添加两列: toy_car_serial
和toy_trains_serial
,都是 NULLABLE,但在提到的表上有FOREIGN KEY
约束。INSERT
都会将序列插入serial_no
和toy_car_serial
或serial_no
和toy_car_serial
。CHECK( toy_car_serial = serial_no OR toy_trains_serial = serial_no)
。我认为两个冗余行和对插入的轻微修改比替代方案少得多。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.