嘿,
我對這里的最佳實踐有疑問。我有一個用作 Postgres 資料庫和特定遷移的 Golang 專案。資料庫有很多表,有些表相互依賴(表 A 有表 B 的 FK,表 B 有表 A 的 FK)。我的“問題”是現在我必須從 CSV 檔案匯入資料,這是我使用 COPY ... FROM ... WITH 命令完成的。每個 CSV 檔案都包含特定表格的資料。
如果我嘗試使用復制命令,我會收到錯誤訊息:“在表“b”上插入或更新違反了外鍵約束”。沒錯,因為表a中現在沒有資料。由于 FK,問題發生在雙方。
那么匯入資料的最佳方式是什么?
謝謝 :)
uj5u.com熱心網友回復:
可能的解決方法:
1.) 創建沒有 FK 約束的表
2.) 將資料加載到表中
3.) 使用 ALTER TABLE 將 FK 約束添加到表中:
例子:
ALTER TABLE table_name
ADD CONSTRAINT constraint_name constraint_definition;
uj5u.com熱心網友回復:
您可以將約束推遲 deferrable到事務結束:
create table a (id serial primary key, b_id bigint);
create table b (id serial primary key, a_id bigint references a(id) deferrable);
alter table a
add constraint fk_b_id foreign key (b_id) references b(id) deferrable;
begin transaction;
SET CONSTRAINTS ALL DEFERRED;
--your `COPY...FROM...WITH` goes here
insert into b values (1,1);--without deferring constraints it fails here
insert into a values (1,1);
commit;
問題是,您必須首先確保您的外鍵約束deferrable- 默認情況下它們不是,所以set constraints all deferred;不會影響它們。
您可以在匯入時動態執行此操作(在線演示):
CREATE TEMP TABLE queries_to_make_constraints_deferrable AS
SELECT format('alter table %I.%I alter constraint %I deferrable',
v.schemaname, v.tablename, con.conname) as query
FROM pg_catalog.pg_constraint con
INNER JOIN pg_catalog.pg_class rel ON rel.oid = con.conrelid
INNER JOIN pg_catalog.pg_namespace nsp ON nsp.oid = connamespace
INNER JOIN (VALUES
('public','table1'),--list your tables here
('public','some_other_table'),
('public','a'),
('public','b')) v(schemaname,tablename)
ON nsp.nspname = v.schemaname AND rel.relname=v.tablename
WHERE con.contype='f' --foreign keys
AND con.condeferrable is False; --non-deferrable
do $$
declare rec record;
begin
for rec in select query from queries_to_make_constraints_deferrable
loop execute rec.query;
end loop;
end $$ ;
deferrable在具有延遲約束的事務中執行匯入,然后通過替換為撤消更改not deferrable:
begin transaction;
SET CONSTRAINTS ALL DEFERRED;
--your `COPY...FROM...WITH` goes here
insert into b values (1,1);--without deferring constraints it fails here
insert into a values (1,1);
commit;
do $$
declare rec record;
begin
for rec in select query from queries_to_make_constraints_deferrable
loop execute replace(rec.query,'deferrable','not deferrable');
end loop;
end $$ ;
如前所述,另一種方法是在沒有這些約束的情況下設定您的架構,并在匯入資料后添加它們。這可能需要您找到它們并將它們與它們的表定義分開,這再次需要類似的動態 sql。
轉載請註明出處,本文鏈接:https://www.uj5u.com/caozuo/534886.html
