本文為英文版的機器翻譯版本,如內容有任何歧義或不一致之處,概以英文版為準。
CREATE PROCEDURE
為目前的資料庫建立新的預存程序或取代現有的程序。
如需詳細資訊和範例,請參閱 在 Amazon Redshift 中建立預存程序。
所需權限
您必須具有下列其中一種執行 CREATE OR REPLACE 的許可PROCEDURE:
-
對於 CREATE PROCEDURE:
-
超級使用者
-
在建立預存程序的結構描述上具有 CREATE和 USAGE權限的使用者
-
-
對於 REPLACE PROCEDURE:
-
超級使用者
-
程序擁有者
-
語法
CREATE [ OR REPLACE ] PROCEDURE sp_procedure_name ( [ [ argname ] [ argmode ] argtype [, ...] ] ) [ NONATOMIC ] AS $$ procedure_body $$ LANGUAGE plpgsql [ { SECURITY INVOKER | SECURITY DEFINER } ] [ SET configuration_parameter { TO value | = value } ]
參數
- 或 REPLACE
-
此子句指定如果已有一個程序的名稱和輸入引數資料類型 (或簽章) 與此程序相同,則取代現有程序。您只能將程序取代為定義一組相同資料類型的新程序。
如果您定義的程序與現有程序同名,但簽章不同,則會建立新程序。換言之,程序名稱是過載。如需詳細資訊,請參閱多載程序名稱。
- sp_procedure_name
-
程序的名稱。如果您指定結構描述名稱 (例如
myschema.myprocedure
),則會在指定的結構描述中建立程序。否則會在目前結構描述中建立程序。如需有效名稱的相關資訊,請參閱 名稱與識別碼。我們建議您在所有預存程序名稱前加上
sp_
。Amazon Redshift 會保留預存程序名稱的sp_
字首。您可以使用sp_
字首,以確保您的預存程序不會與任何現有或未來的 Amazon Redshift 內建預存程序或函數名稱發生衝突。如需詳細資訊,請參閱命名預存程序。如果輸入引數的資料類型 (或簽章) 不同,您可以定義多個同名的程序。換言之,在此情況下程序名稱是過載。如需詳細資訊,請參閱 多載程序名稱
- [argname] [ argmode] argtype
-
引數名稱、引數模式和資料類型的清單。僅資料類型是必要的。名稱和模式是選用的,其位置可調換。
引數模式可以是 IN、 OUT或 INOUT。預設值為 IN。
您可以使用 OUT和 INOUT引數,從程序呼叫傳回一或多個值。有 OUT或 INOUT引數時,程序呼叫會傳回一個包含 n 資料欄的結果列,其中 n 是 OUT或 INOUT引數的總數。
INOUT 引數是同時輸入和輸出引數。輸入引數包含 IN 和INOUT引數,而輸出引數包含 OUT和 INOUT引數。
OUT 引數不會指定為CALL陳述式的一部分。在預存程序CALL陳述式中指定INOUT引數。INOUT 從巢狀呼叫傳遞和傳回值,以及傳回 時,引數非常有用
refcursor
。如需refcursor
類型的詳細資訊,請參閱游標。引數資料類型可以是任何標準 Amazon Redshift 資料類型。此外,引數資料類型還可以是
refcursor
。您最多可以指定 32 個輸入引數和 32 個輸出引數。
- AS $$ procedure_body $$
-
包圍要執行之程序的結構。常值關鍵字 AS $$ 和 $$ 是必要的。
Amazon Redshift 會要求您使用稱為 $ 符號引用的格式包圍程序中的陳述式。包圍範圍當中的任何內容都會原封不動傳遞。您不需要逸出任何特殊字元,因為字串的內容是逐字撰寫。
使用 $ 符號引用時,您會使用一組 $$ 符號配對表示要執行之陳述式的開頭和結尾,如以下範例所示。
$$ my statement $$
您也可以選擇在每組配對的兩個 $ 符號之間指定字串來協助識別陳述式。您在包圍配對的開頭和結尾中使用的字串必須相同。此字串區分大小寫,且遵循與未加引號的識別碼相同的限制條件,不過後者不可包含 $ 符號。下列範例使用字串 test。
$test$ my statement $test$
此語法也適用於巢狀 $ 符號引用。如需美元報價的詳細資訊,請參閱 PostgreSQL 文件的 Lexical Structure
下的「美元報價字串常數」。 - procedure_body
-
一組有效的 PL/pgSQL 陳述式。PL/pgSQL 陳述式使用程序建構增強SQL命令,包括迴圈和條件式表達式,以控制邏輯流程。大多數SQL命令都可以在程序內文中使用,包括資料修改語言 (DML),例如 COPY、 UNLOAD和 INSERT,以及資料定義語言 (DDL),例如 CREATE TABLE。如需詳細資訊,請參閱PL/pgSQL 語言參考。
- LANGUAGE plpgsql
-
語言值。指定
plpgsql
。您必須具有語言的使用許可,才能使用plpgsql
。如需詳細資訊,請參閱GRANT。 - NONATOMIC
-
在非原子交易模式中建立預存程序。NONATOMIC 模式會自動遞交程序中的陳述式。此外,當NONATOMIC程序內發生錯誤時,如果錯誤是由例外區塊處理,則不會重新擲回錯誤。如需詳細資訊,請參閱 管理交易 和 RAISE。
將預存程序定義為
NONATOMIC
時,請考慮下列事項:當您巢狀化預存程序呼叫時,必須以相同的交易模式建立所有程序。
在 NONATOMIC 模式下建立程序時,不支援
SECURITY DEFINER
選項和SET configuration_parameter
選項。處理隱含遞交時,任何已開啟的 (明確或隱含) 游標皆會自動關閉。因此,您必須先開啟明確的交易,才能開始游標迴圈,以確保迴圈的反覆運算SQL中的任何 不會隱含遞交。
- SECURITY INVOKER | SECURITY DEFINER
-
指定
NONATOMIC
時不支援SECURITY DEFINER
選項。程序的安全模式決定程序在執行時間的存取權限。程序必須有存取基礎資料庫物件的許可。
對於 SECURITY INVOKER 模式,程序會使用呼叫程序之使用者的權限。使用者必須具有基礎資料庫物件的明確權限。預設值為 SECURITY INVOKER。
對於 SECURITY DEFINER 模式,程序會使用程序擁有者的權限。程序擁有者定義為在執行階段擁有該程序的使用者,而不一定是最初定義程序的使用者。呼叫程序的使用者必須有程序的執行權限,但不需要基礎物件的任何權限。
- SET configuration_parameter { TO value | = value }
-
指定
NONATOMIC
時不支援這些選項。SET 子句會在輸入程序時將指定的
configuration_parameter
設定為指定的值。當程序離開時,此子句會接著將configuration_parameter
還原到先前的值。
使用須知
如果使用 SECURITYDEFINER選項建立預存程序,則在預存程序中叫用 CURRENT_USER 函數時,Amazon Redshift 會傳回預存程序擁有者的使用者名稱。
範例
注意
如果在執行這些範例時,您遇到類似以下的錯誤:
ERROR: 42601: [Amazon](500310) unterminated dollar-quoted string at or near "$$
下列範例建立具有兩個輸入參數的程序。
CREATE OR REPLACE PROCEDURE test_sp1(f1 int, f2 varchar(20)) AS $$ DECLARE min_val int; BEGIN DROP TABLE IF EXISTS tmp_tbl; CREATE TEMP TABLE tmp_tbl(id int); INSERT INTO tmp_tbl values (f1),(10001),(10002); SELECT INTO min_val MIN(id) FROM tmp_tbl; RAISE INFO 'min_val = %, f2 = %', min_val, f2; END; $$ LANGUAGE plpgsql;
注意
當您撰寫預存程序時,我們建議您採用保護敏感值的最佳作法:
不要在預存程序邏輯中對任何敏感資訊進行硬式編碼。例如,請勿在儲存程序內文的CREATEUSER陳述式中指派使用者密碼。這會造成安全性風險,因為硬式編碼值可以記錄為目錄資料表中的結構描述資料。應改為透過參數將敏感值 (例如密碼) 當做引數傳遞給預存程序。
如需預存程序的詳細資訊,請參閱 CREATEPROCEDURE和在 Amazon Redshift 中建立預存程序。如需目錄資料表的相關資訊,請參閱系統目錄資料表。
下列範例會建立具有一個 IN 參數、一個 OUT 參數和一個 INOUT 參數的程序。
CREATE OR REPLACE PROCEDURE test_sp2(f1 IN int, f2 INOUT varchar(256), out_var OUT varchar(256)) AS $$ DECLARE loop_var int; BEGIN IF f1 is null OR f2 is null THEN RAISE EXCEPTION 'input cannot be null'; END IF; DROP TABLE if exists my_etl; CREATE TEMP TABLE my_etl(a int, b varchar); FOR loop_var IN 1..f1 LOOP insert into my_etl values (loop_var, f2); f2 := f2 || '+' || f2; END LOOP; SELECT INTO out_var count(*) from my_etl; END; $$ LANGUAGE plpgsql;