2011-11-30 54 views
32

我檢查了Oracle提供的文檔,發現了一種修改約束而不刪除表的方法。問題是,它在修改時出錯,因爲它無法識別關鍵字。試圖修改PostgreSQL中的約束條件

將EMS SQL管理器用於PostgreSQL。

Alter table public.public_insurer_credit MODIFY CONSTRAINT public_insurer_credit_fk1 
    deferrable, initially deferred; 

我能夠通過降低使用約束來解決它:

ALTER TABLE "public"."public_insurer_credit" 
    DROP CONSTRAINT "public_insurer_credit_fk1" RESTRICT; 

ALTER TABLE "public"."public_insurer_credit" 
    ADD CONSTRAINT "public_insurer_credit_fk1" FOREIGN KEY ("branch_id", "order_id", "public_insurer_id") 
    REFERENCES "public"."order_public_insurer"("branch_id", "order_id", "public_insurer_id") 
    ON UPDATE CASCADE 
    ON DELETE NO ACTION 
    DEFERRABLE 
    INITIALLY DEFERRED; 
+9

爲什麼在使用PostgreSQL時檢查Oracle文檔(並用'plsql'標記此問題)?什麼是確切的錯誤(哪個關鍵字不被識別)? – Bruno

+0

ERROR:語法錯誤處或附近 「修改」 LINE 1:ALTER TABLE public.public_insurer_credit MODIFY約束p ... ^ (0.359秒) – MISMajorDeveloperAnyways

+7

檢查的Postgres的Oracle的文檔,然後指責Postgres的。史詩。 –

回答

23

按照正確的手冊(由PostgreSQL的供應,不受Oracle),沒有任何修改約束可在ALTER TABLE語句:

這裏是鏈接到正確的手冊:

http://www.postgresql.org/docs/current/static/sql-altertable.html

+0

感謝您提供正確文檔的鏈接。我提供了來自我們DBA的Oracle PL/SQL文檔。人物。 – MISMajorDeveloperAnyways

+2

Oracle和Oracle的PL/SQL是完全不同的東西。他們這樣做的唯一可能原因是因爲您正在使用支持Oracle PL/SQL(以及其他Oracle兼容性功能)的EnterpriseDB * Advanced Server *。但是,他們應該給你EnterpriseDB手冊,而不是Oracle手冊 –

+1

任何人都可以解釋爲什麼這個答案得到一個downvote? –

52

對於Postgres中的約束,沒有ALTER命令。最簡單的方法是下降約束並重新添加所需的參數。當然,約束的任何更改都將針對當前表數據運行。

BEGIN; 
ALTER TABLE t1 DROP CONSTRAINT ... 
ALTER TABLE t1 ADD CONSTRAINT ... 
COMMIT; 
+14

+1在交易中使用。 –

+5

請注意:如果我理解正確,DDL語句會在表上使用AccessExclusive鎖,因此如果這些命令需要很長時間,您的站點將停止運行,直到命令完成。 [文檔頁面](http://www.postgresql.org/docs/current/static/sql-altertable.html)有更多詳細信息,包括如何顯式指定索引而不是自動生成索引。 –

25

從版本9.4開始,PostgreSQL支持外鍵的ALTER TABLE ... ALTER CONSTRAINT

此功能將"Allow constraint attributes to be altered, so the default setting of NOT DEFERRABLE can be altered to DEFERRABLE and back."看看你的問題,我認爲這是(種)你一直在尋找。

更詳細的信息和示例可以在這裏找到:
http://www.depesz.com/2013/06/30/waiting-for-9-4-alter-table-alter-constraint-for-fks/

+2

http://www.postgresql.org/docs/9.4/static/sql-altertable.html –

+1

請注意,9.4文檔說'目前只有外鍵約束可能會改變.'! –

+0

@MichaelHerrmann我已經在我的回答中提到了這一點。 – mkurz

2

ALTER約束將需要知道外鍵的名字,這並不總是很方便的。

這裏是函數,你只需要知道表名和列名。 用法:

select replace_foreign_key('user_rates_posts', 'post_id', 'ON DELETE CASCADE'); 

功能:

CREATE OR REPLACE FUNCTION 
    replace_foreign_key(f_table VARCHAR, f_column VARCHAR, new_options VARCHAR) 
RETURNS VARCHAR 
AS $$ 
DECLARE constraint_name varchar; 
DECLARE reftable varchar; 
DECLARE refcolumn varchar; 
BEGIN 

SELECT tc.constraint_name, ccu.table_name AS foreign_table_name, ccu.column_name AS foreign_column_name 
FROM 
    information_schema.table_constraints AS tc 
    JOIN information_schema.key_column_usage AS kcu 
     ON tc.constraint_name = kcu.constraint_name 
    JOIN information_schema.constraint_column_usage AS ccu 
     ON ccu.constraint_name = tc.constraint_name 
WHERE constraint_type = 'FOREIGN KEY' 
    AND tc.table_name= f_table AND kcu.column_name= f_column 
INTO constraint_name, reftable, refcolumn; 

EXECUTE 'alter table ' || f_table || ' drop constraint ' || constraint_name || 
', ADD CONSTRAINT ' || constraint_name || ' FOREIGN KEY (' || f_column || ') ' || 
' REFERENCES ' || reftable || '(' || refcolumn || ') ' || new_options || ';'; 

RETURN 'Constraint replaced: ' || constraint_name || ' (' || f_table || '.' || f_column || 
' -> ' || reftable || '.' || refcolumn || '); New options: ' || new_options; 

END; 
$$ LANGUAGE plpgsql; 

注意:此功能不會複製初始外鍵的屬性。 它只需要外國名稱/列名稱,丟棄當前密鑰,並用新的代替

+0

非常有趣的解決方案 – tom10271