繁体   English   中英

REFERENCES 两个不同表中的两个不同列

[英]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_carstoy_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 约束中

我非常喜欢这个,因为它在概念上非常简单且易于掌握。 认为它只涉及以下步骤:

  1. ALTER TABLE添加两列: toy_car_serialtoy_trains_serial ,都是 NULLABLE,但在提到的表上有FOREIGN KEY约束。
  2. 确保任何INSERT都会将序列插入serial_notoy_car_serialserial_notoy_car_serial
  3. 添加CHECK( toy_car_serial = serial_no OR toy_trains_serial = serial_no)

我认为两个冗余行和对插入的轻微修改比替代方案少得多。

暂无
暂无

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

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