在數據庫中模擬Tagged union的最佳方法是什麼? 我說的是這樣的:如何模擬數據庫中的標記聯合?
create table t1 {
vehicle_id INTEGER NOT NULL REFERENCES car(id) OR motor(id) -- not valid
...
}
其中vehicle_id將汽車表或電機表ID,它會知道。
(假設電機和車載臺也沒什麼common0
在數據庫中模擬Tagged union的最佳方法是什麼? 我說的是這樣的:如何模擬數據庫中的標記聯合?
create table t1 {
vehicle_id INTEGER NOT NULL REFERENCES car(id) OR motor(id) -- not valid
...
}
其中vehicle_id將汽車表或電機表ID,它會知道。
(假設電機和車載臺也沒什麼common0
有些人使用一種叫做多態關聯做這個設計,讓vehicle_id
包含存在無論是在car
或motor
表的值,然後添加一個vehicle_type
,它命名t1
中給定的行的表
問題是,如果你這樣做,你不能聲明一個真正的SQL外鍵約束在SQL中沒有支持的外鍵含多處參考目標。還有其他問題,但缺乏參照完整性已經成爲一種破壞行爲。
更好的設計是從兩個car
和motor
的常見的超的面向對象的設計借用一個概念:
CREATE TABLE Identifiable (
id SERIAL PRIMARY KEY
);
然後讓t1
參考此超表:
CREATE TABLE t1 (
vehicle_id INTEGER NOT NULL,
FOREIGN KEY (vehicle_id) REFERENCES identifiable(id)
...
);
還使子類型引用其父超類型。請注意,子類型的主鍵是而不是自動遞增。父超類型負責分配一個新的id值,而孩子只引用該值。
CREATE TABLE car (
id INTEGER NOT NULL,
FOREIGN KEY (id) REFERENCES identifiable(id)
...
);
CREATE TABLE motor (
id INTEGER NOT NULL,
FOREIGN KEY (id) REFERENCES identifiable(id)
...
);
現在你可以有真正的參照完整性,而且還支持多種亞型表有自己的屬性。
通過@Quassnoi答案還示出了執行不相交亞型的方法。也就是說,要防止car
和motor
引用其父超類型表中的同一行。當我這樣做時,我使用單列主鍵Identifiable.id
,但也通過Identifiable.(id, type)
聲明UNIQUE
鍵。 car
和motor
中的外鍵可以引用兩列唯一鍵而不是主鍵。
CREATE TABLE vehicle (type INT NOT NULL, id INT NOT NULL,
PRIMARY KEY (type, id)
)
CREATE TABLE car (type INT NOT NULL DEFAULT 1, id INT NOT NULL PRIMARY KEY,
CHECK(type = 1),
FOREIGN KEY (type, id) REFERENCES vehicle
)
CREATE TABLE motorcycle (type INT NOT NULL DEFAULT 2, id INT NOT NULL PRIMARY KEY,
CHECK(type = 2),
FOREIGN KEY (type, id) REFERENCES vehicle
)
CREATE TABLE t1 (
...
vehicle_type INT NOT NULL,
vehicle_id INT NOT NULL,
FOREIGN KEY (vehicle_type, vehicle_id) REFERENCES vehicle
...
)
它會做如果將'VEHICLE.VEHICLE_ID'定義爲主鍵,那麼生活就會更簡單,因此您不必引用組合鍵,並使用唯一約束來鍵入&id列。 – 2009-11-13 17:36:43
'@OMG小馬:'有了這個佈局,你根本不需要參考'車輛'。你可以加入'汽車'或'摩托車',這取決於'類型'。這裏的「車輛」只是爲了警告關係。 – Quassnoi 2009-11-13 17:50:50
用這種方法,有沒有辦法保證在「汽車」或「摩托車」中沒有相應的行的「孤兒」汽車? – 2017-09-25 21:31:23
我想你可以使用table inheritance in PostgreSQL來建模這樣的參考。
如果你真的需要知道在哪裏一行來自於查詢,你可以使用一個簡單的UNION ALL statment像(這種可能性有沒有關係表繼承):
SELECT car.*, 'car' table_name
UNION ALL
SELECT motor.*, 'motor' table_name
「可識別」的代理鍵只有在查詢需要選擇的「可識別」屬性中才有用。如果「可識別」僅用於強制執行約束,則使用複合密鑰將允許在查詢中競爭地擺脫它。 – Quassnoi 2009-11-13 17:54:10
我想出了自己使用的'共同超類型'方法,並在主要的系統遷移/重建項目中成功地使用了它。 (新西蘭政府,教育部SPOT25) – 2012-06-26 22:52:01