PostgreSQL 中的基本事務 DDL 腳本
PostgreSQL 新手在這裡嘗試將事務 DDL 腳本放在一起,以在 Postgres 9.3 中原子地創建數據庫及其模式:在事務中,創建幾個表;如果有任何錯誤,請將整個內容回滾;否則送出。我很難獲得正確的語法,我懷疑我的問題可能源於將 SQL DDL 與 PL/pgSQL 混為一談和/或沒有理解事務語義。
長話短說,執行此類操作的腳本的 PL/pgSQL 樣板是什麼?
我的嘗試是這樣
schema.sql
的:BEGIN; CREATE TABLE IF NOT EXISTS blah ( ... ); -- much DDL EXCEPTION WHEN OTHERS THEN ROLLBACK; -- this, I gather, is PL/pgSQL COMMIT;
\i schema.sql
在 psql 提示符處或附近產生語法錯誤EXCEPTION
。好的,所以EXCEPTION
必須是 PL/pgSQL,所有這些都需要放在 PL/pgSQL 聲明中。讓我們再試一次:根據http://www.postgresql.org/docs/9.3/static/plpgsql-structure.html的語法,這看起來像:
[ <<label>> ] [ DECLARE declarations ] BEGIN statements END [ label ];
我不需要命名它,它是一次性配置腳本,而不是聲明我將再次使用的函式。所以跳過聲明並擴展
statements
到我之前的內容:BEGIN BEGIN; CREATE TABLE IF NOT EXISTS blah ( ... ); -- much DDL EXCEPTION WHEN OTHERS THEN ROLLBACK; COMMIT; END;
這以更糟糕的方式爆發,出現語法錯誤
BEGIN
,EXCEPTION
,然後它繼續執行腳本的其餘部分,抱怨不在事務中。我這裡有什麼誤解?
如果有任何錯誤,請將整個內容回滾;
它比你想像的要簡單。事務中的任何異常(未以某種方式被擷取)都會自動
ROLLBACK
觸發整個事務。你不必做任何額外的事情。BEGIN; CREATE TABLE IF NOT EXISTS blah ( ... ); -- much more DDL COMMIT;
您根本無法在plpgsql中啟動、送出或回滾事務,因為 plpgsql 塊總是在外部事務的上下文中自動執行。
不要將用於事務管理的 SQL 命令與plpgsql 程式碼塊的元素混淆。
BEGIN
在兩者中都用作關鍵字,這是唯一的共同點。這絕不是模棱兩可的,因為 SQL 命令在 plpgsql 程式碼中不可用,並且在 plpgsql 程式碼塊之外沒有 plpgsql 命令。plpgsql 塊中的
EXCEPTION
子句僅用於擷取錯誤並在ROLLBACK
. 當然,只有做一些ROLLBACK
不會撤消的事情才有意義——比如提出一個永遠不會回滾的消息。您的展示程式碼不需要任何這些。