Postgresql

如何在沒有外鍵檢查的情況下創建表之間的關係元數據?

  • November 14, 2018

我使用數據庫元數據(主鍵、外鍵、表名等)來生成程式碼和一些非常複雜的查詢。此元數據位於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,因為BA沒有的值。

問題

基本上,我在一些類似“多對多”的關係方面遇到了問題。

我想過禁用外鍵檢查,然後在 上創建外鍵B.ColumnA,但我還沒有找到一種方法來禁用僅對一個特定約束的檢查,因為我仍然想保持B.ColumnC外鍵上的數據完整性。

有沒有辦法在不失去數據完整性的情況下創建關係BA最好不創建任何額外的表或列?

編輯:我正在使用 Postgres,但我會用“數據庫不可知論”來標記它,以查看其他供應商的解決方案是否可以移植到我的案例中。

添加一個新表和適當的外鍵可能是解決這個問題的更自然的方法。

在某些 DBMS(例如 SQL SQL Server)中,您可以使用以下命令創建禁用或禁用現有外鍵約束ALTER TABLE .. NOCHECK CONSTRAINT

ALTER TABLE b NOCHECK CONSTRAINT [a_b_fk] ;

在 Postgres 中,如果您真的不想或不允許更改架構,您可以從Ato創建一個外鍵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=# 

引用自:https://dba.stackexchange.com/questions/222541