[英]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.