

 Amazon Redshift 將不再支援從修補程式 198 開始建立新的 Python UDFs。現有 Python UDF 將繼續正常運作至 2026 年 6 月 30 日。如需詳細資訊，請參閱[部落格文章](https://aws.amazon.com/blogs/big-data/amazon-redshift-python-user-defined-functions-will-reach-end-of-support-after-june-30-2026/)。

本文為英文版的機器翻譯版本，如內容有任何歧義或不一致之處，概以英文版為準。

# CREATE PROCEDURE
<a name="r_CREATE_PROCEDURE"></a>

為目前的資料庫建立新的預存程序或取代現有的程序。

如需詳細資訊和範例，請參閱 [在 Amazon Redshift 中建立預存程序](stored-procedure-overview.md)。

## 所需權限
<a name="r_CREATE_PROCEDURE-privileges"></a>

您必須具有下列其中一種方式取得的許可，才能執行 CREATE OR REPLACE PROCEDURE：
+ 對於 CREATE PROCEDURE：
  + 超級使用者
  + 建立預存程序的結構描述上具有 CREATE 和 USAGE 權限的使用者
+ 對於 REPLACE PROCEDURE：
  + 超級使用者
  + 程序擁有者

## 語法
<a name="r_CREATE_PROCEDURE-synopsis"></a>

```
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 } ]
```

## Parameters
<a name="r_CREATE_PROCEDURE-parameters"></a>

 OR REPLACE   
此子句指定如果已有一個程序的名稱和輸入引數資料類型 (或簽章) 與此程序相同，則取代現有程序。您只能將程序取代為定義一組相同資料類型的新程序。  
如果您定義的程序與現有程序同名，但簽章不同，則會建立新程序。換言之，程序名稱是過載。如需詳細資訊，請參閱[多載程序名稱](stored-procedure-naming.md#stored-procedure-overloading-name)。

 *sp\$1procedure\$1name*   
程序的名稱。如果您指定結構描述名稱 (例如 **myschema.myprocedure**)，則會在指定的結構描述中建立程序。否則會在目前結構描述中建立程序。如需有效名稱的相關資訊，請參閱 [名稱與識別碼](r_names.md)。  
我們建議您在所有預存程序名稱前加上 `sp_`。Amazon Redshift 會保留預存程序名稱的 `sp_` 字首。您可以使用 `sp_` 字首，以確保您的預存程序不會與任何現有或未來的 Amazon Redshift 內建預存程序或函數名稱發生衝突。如需詳細資訊，請參閱[命名預存程序](stored-procedure-naming.md)。  
如果輸入引數的資料類型 (或簽章) 不同，您可以定義多個同名的程序。換言之，在此情況下程序名稱是過載。如需詳細資訊，請參閱[多載程序名稱](stored-procedure-naming.md#stored-procedure-overloading-name)

*[argname] [ argmode] argtype*   
引數名稱、引數模式和資料類型的清單。僅資料類型是必要的。名稱和模式是選用的，其位置可調換。  
引數模式可以是 IN、OUT 或 INOUT。預設值為 IN。  
您可以使用 OUT 和 INOUT 引數，從程序呼叫傳回一或多個值。有 OUT 或 INOUT 引數時，程序呼叫會傳回一個包含 *n* 欄的結果列，其中 *n* 是 OUT 或 INOUT 引數總數。  
INOUT 引數同時為輸入和輸出引數。*輸入引數*包括 IN 和 INOUT 引數，*輸出引數*包括 OUT 和 INOUT 引數。  
CALL 陳述式中不指定 OUT 引數。在預存程序 CALL 陳述式中，請指定 INOUT 引數。從巢狀呼叫傳遞和傳回值，以及傳回 `refcursor` 時，INOUT 引數可能很有用。如需 `refcursor` 類型的詳細資訊，請參閱[游標](c_PLpgSQL-statements.md#r_PLpgSQL-cursors)。  
引數資料類型可以是任何標準 Amazon Redshift 資料類型。此外，引數資料類型還可以是 `refcursor`。  
您最多可以指定 32 個輸入引數和 32 個輸出引數。

AS \$1\$1 *procedure\$1body* \$1\$1   
包圍要執行之程序的結構。常值關鍵字 AS \$1\$1 和 \$1\$1 是必要的。  
Amazon Redshift 會要求您使用稱為 \$1 符號引用的格式包圍程序中的陳述式。包圍範圍當中的任何內容都會原封不動傳遞。您不需要逸出任何特殊字元，因為字串的內容是逐字撰寫。  
使用 *\$1 符號引用*時，您會使用一組 \$1\$1 符號配對表示要執行之陳述式的開頭和結尾，如以下範例所示。  

```
$$ my statement $$
```
您也可以選擇在每組配對的兩個 \$1 符號之間指定字串來協助識別陳述式。您在包圍配對的開頭和結尾中使用的字串必須相同。此字串區分大小寫，且遵循與未加引號的識別碼相同的限制條件，不過後者不可包含 \$1 符號。下列範例使用字串 test。  

```
$test$ my statement $test$
```
此語法也適用於巢狀 \$1 符號引用。如需 \$1 符號引用的詳細資訊，請參閱 PostgreSQL 文件中的[辭典結構](https://www.postgresql.org/docs/9.0/sql-syntax-lexical.html)下的「\$1 符號引用的字串常數」。

 *procedure\$1body*   
一組有效的 PL/pgSQL 陳述式。PL/pgSQL 陳述式以程序性建構 (包括迴圈和條件式表達式) 來擴增 SQL 命令，以控制邏輯流程。大部分 SQL 命令可用於程序主體中，包括資料修改語言 (DML) (例如 COPY、UNLOAD 和 INSERT) 和資料定義語言 (DDL) (例如 CREATE TABLE)。如需詳細資訊，請參閱[PL/pgSQL 語言參考](c_pl_pgSQL_reference.md)。

LANGUAGE *plpgsql*  
語言值。指定 `plpgsql`。您必須具有語言的使用許可，才能使用 `plpgsql`。如需詳細資訊，請參閱[GRANT](r_GRANT.md)。

NONATOMIC  
在非原子交易模式中建立預存程序。NONATOMIC 模式會自動提交程序中的陳述式。此外，當 NONATOMIC 程序內部發生錯誤時，如果錯誤是由例外狀況區塊處理，則不會重新擲回錯誤。如需詳細資訊，請參閱[管理交易](stored-procedure-transaction-management.md)及[RAISE](c_PLpgSQL-statements.md#r_PLpgSQL-messages-errors)。  
將預存程序定義為 `NONATOMIC` 時，請考慮下列事項：  
+ 當您巢狀化預存程序呼叫時，必須以相同的交易模式建立所有程序。
+ 在 NONATOMIC 模式下建立程序時，不支援 `SECURITY DEFINER` 選項和 `SET configuration_parameter` 選項。
+ 處理隱含遞交時，任何已開啟的 (明確或隱含) 游標皆會自動關閉。因此，您必須在開始游標循環之前開啟明確的交易，以確保循環迭代中的任何 SQL 都不會隱含遞交。

SECURITY INVOKER \$1 SECURITY DEFINER  
指定 `NONATOMIC` 時不支援 `SECURITY DEFINER` 選項。  
程序的安全模式決定程序在執行時間的存取權限。程序必須有存取基礎資料庫物件的許可。  
若為 SECURITY INVOKER 模式，程序會使用呼叫程序的使用者的權限。使用者必須具有基礎資料庫物件的明確權限。預設為 SECURITY INVOKER。  
對於 SECURITY DEFINER 模式，程序會使用程序擁有者的權限。程序擁有者定義為在執行階段擁有該程序的使用者，而不一定是最初定義程序的使用者。呼叫程序的使用者必須有程序的執行權限，但不需要基礎物件的任何權限。

SET configuration\$1parameter \$1 TO value \$1 = value \$1  
指定 `NONATOMIC` 時不支援這些選項。  
SET 子句會在進入程序時將指定的 `configuration_parameter` 設為指定的值。當程序離開時，此子句會接著將 `configuration_parameter` 還原到先前的值。

## 使用須知
<a name="r_CREATE_PROCEDURE-usage"></a>

如果使用 SECURITY DEFINER 選項建立預存程序，則在從預存程序中調用 CURRENT\$1USER 函數時，Amazon Redshift 會傳回預存程序擁有者的使用者名稱。

## 範例
<a name="r_CREATE_PROCEDURE-examples"></a>

**注意**  
如果在執行這些範例時，您遇到類似以下的錯誤：  

```
ERROR: 42601: [Amazon](500310) unterminated dollar-quoted string at or near "$$
```
請參閱 [Amazon Redshift 中的預存程序概觀](stored-procedure-create.md)。

下列範例建立具有兩個輸入參數的程序。

```
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 min_val MIN(id) FROM tmp_tbl;
  RAISE INFO 'min_val = %, f2 = %', min_val, f2;
END;
$$ LANGUAGE plpgsql;
```

**注意**  
 當您撰寫預存程序時，我們建議您採用保護敏感值的最佳作法：  
 不要在預存程序邏輯中對任何敏感資訊進行硬式編碼。例如，請勿在預存程序主體的 CREATE USER 陳述式中指派使用者密碼。這會造成安全性風險，因為硬式編碼值可以記錄為目錄資料表中的結構描述資料。應改為透過參數將敏感值 (例如密碼) 當做引數傳遞給預存程序。  
如需預存程序的相關資訊，請參閱 [CREATE PROCEDURE](https://docs.aws.amazon.com/redshift/latest/dg/r_CREATE_PROCEDURE.html) 和[在 Amazon Redshift 中建立預存程序](https://docs.aws.amazon.com/redshift/latest/dg/stored-procedure-overview.html)。如需目錄資料表的相關資訊，請參閱[系統目錄資料表](https://docs.aws.amazon.com/redshift/latest/dg/c_intro_catalog_views.html)。

下列範例建立具有一個 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;
```

下列範例會建立使用 `SECURITY DEFINER` 參數的程序。此程序會使用擁有程序之使用者的權限來執行。

```
CREATE OR REPLACE PROCEDURE sp_get_current_user_definer()
AS $$
DECLARE curr_user varchar(250);
BEGIN
  SELECT current_user INTO curr_user;
  RAISE INFO '%', curr_user;
END;
$$ LANGUAGE plpgsql
SECURITY DEFINER;
```

下列範例會建立使用 `SECURITY INVOKER` 參數的程序。此程序會使用執行程序之使用者的權限來執行。

```
CREATE OR REPLACE PROCEDURE sp_get_current_user_invoker()
AS $$
DECLARE curr_user varchar(250);
BEGIN
  SELECT current_user INTO curr_user;
  RAISE INFO '%', curr_user;
END;
$$ LANGUAGE plpgsql
SECURITY INVOKER;
```