如何在沒有外鍵檢查的情況下創建表之間的關係元數據?
我使用數據庫元數據(主鍵、外鍵、表名等)來生成程式碼和一些非常複雜的查詢。此元數據位於
INFORMATION_SCHEMA
. 我在使用以下(簡化的)案例時遇到問題:表
table A
(與ID
)
table B
(與ID
,ColumnA
,ColumnC
)
table C
(與ID
)所有
ID
列都是唯一的,ColumnA
並且ColumnC
具有重複的值情況
ColumnC
具有來自 的值的子集,C
換句話說,B
永遠不會有沒有的值C
。
ColumnA
具有來自 的值的非完美超集,A
換句話說,B
具有獨占值和 的幾乎所有值A
,但A
也很少具有獨占值。問題
B.ColumnC
引用之間有一個外鍵C.ID
,它按預期工作。
B.ColumnA
現在,由於外鍵的性質,引用時沒有外鍵A.ID
,因為B
有A
沒有的值。問題
基本上,我在一些類似“多對多”的關係方面遇到了問題。
我想過禁用外鍵檢查,然後在 上創建外鍵
B.ColumnA
,但我還沒有找到一種方法來禁用僅對一個特定約束的檢查,因為我仍然想保持B.ColumnC
外鍵上的數據完整性。有沒有辦法在不失去數據完整性的情況下創建關係
B
,A
最好不創建任何額外的表或列?編輯:我正在使用 Postgres,但我會用“數據庫不可知論”來標記它,以查看其他供應商的解決方案是否可以移植到我的案例中。
添加一個新表和適當的外鍵可能是解決這個問題的更自然的方法。
在某些 DBMS(例如 SQL SQL Server)中,您可以使用以下命令創建禁用或禁用現有外鍵約束
ALTER TABLE .. NOCHECK CONSTRAINT
:ALTER TABLE b NOCHECK CONSTRAINT [a_b_fk] ;
在 Postgres 中,如果您真的不想或不允許更改架構,您可以從
A
to創建一個外鍵B
,然後禁用與之關聯的內部觸發器。沒有辦法(據我所知)將外鍵約束標記為“禁用”,但禁用內部觸發器會產生預期的效果。創建表
blue=# create table a (id int primary key) ; CREATE TABLE blue=# create table b (id int primary key, aid int not null) ; CREATE TABLE
添加外鍵約束
blue=# alter table b add constraint a_b_fk foreign key (aid) references a(id) ; ALTER TABLE
查找觸發器名稱
blue=# SELECT tgname, tgconstraint FROM pg_trigger WHERE tgrelid = 'public.a'::regclass; tgname | tgconstraint --------------------------------+-------------- RI_ConstraintTrigger_a_3657774 | 3657773 RI_ConstraintTrigger_a_3657775 | 3657773 (2 rows) blue=# SELECT tgname, tgconstraint FROM pg_trigger WHERE tgrelid = 'public.b'::regclass; tgname | tgconstraint --------------------------------+-------------- RI_ConstraintTrigger_c_3657776 | 3657773 RI_ConstraintTrigger_c_3657777 | 3657773 (2 rows)
禁用觸發器
blue=# alter table a disable trigger "RI_ConstraintTrigger_a_3657774" ; ALTER TABLE blue=# alter table a disable trigger "RI_ConstraintTrigger_a_3657775" ; ALTER TABLE blue=# alter table b disable trigger "RI_ConstraintTrigger_c_3657776" ; ALTER TABLE blue=# alter table b disable trigger "RI_ConstraintTrigger_c_3657777" ; ALTER TABLE blue=#
我們現在可以隨意插入值,不檢查 FOREIGN KEY
blue=# insert into a (id) values (1), (2), (3) ; INSERT 0 3 blue=# insert into b (id, aid) values (1,1), (2,1), (4,4) ; INSERT 0 3
顯示表的結構
blue=# \d a Table "public.a" Column | Type | Collation | Nullable | Default --------+---------+-----------+----------+--------- id | integer | | not null | Indexes: "a_pkey" PRIMARY KEY, btree (id) Referenced by: TABLE "b" CONSTRAINT "a_b_fk" FOREIGN KEY (aid) REFERENCES a(id) Disabled internal triggers: "RI_ConstraintTrigger_a_3657774" AFTER DELETE ON a FROM b NOT DEFERRABLE INITIALLY IMMEDIATE FOR EACH ROW EXECUTE PROCEDURE "RI_FKey_noaction_del"() "RI_ConstraintTrigger_a_3657775" AFTER UPDATE ON a FROM b NOT DEFERRABLE INITIALLY IMMEDIATE FOR EACH ROW EXECUTE PROCEDURE "RI_FKey_noaction_upd"() blue=# \d b Table "public.b" Column | Type | Collation | Nullable | Default --------+---------+-----------+----------+--------- id | integer | | not null | aid | integer | | not null | Indexes: "b_pkey" PRIMARY KEY, btree (id) Foreign-key constraints: "a_b_fk" FOREIGN KEY (aid) REFERENCES a(id) Disabled internal triggers: "RI_ConstraintTrigger_c_3657776" AFTER INSERT ON b FROM a NOT DEFERRABLE INITIALLY IMMEDIATE FOR EACH ROW EXECUTE PROCEDURE "RI_FKey_check_ins"() "RI_ConstraintTrigger_c_3657777" AFTER UPDATE ON b FROM a NOT DEFERRABLE INITIALLY IMMEDIATE FOR EACH ROW EXECUTE PROCEDURE "RI_FKey_check_upd"() blue=#