1. 程式人生 > >Postgresql - plpgsql - Control Structures

Postgresql - plpgsql - Control Structures

本文內容均翻譯自官方文件

https://www.postgresql.org/docs/10/static/plpgsql-control-structures.html#PLPGSQL-STATEMENTS-RETURNING

========================================================

 

1. IF-THEN

是使用IF最簡單的形式,如果條件為真,則執行,否則跳過。

Example:

IF v_user_id <> 0 THEN

UPDATE users SET email = v_email WHERE user_id = v_user_id;

END IF;

 

2. IF-THEN-ELSE

它允許指定一組備選語句,如果條件不為真,則應該執行這些語句。(注意,這包括條件為空的情況)。

Example:

IF parentid IS NULL OR parentid = ''

THEN

RETURN fullname;

ELSE

RETURN hp_true_filename(parentid) || '/' || fullname;

END IF;

 

3. IF-THEN-ELSIF

有時有兩個以上的選擇。IF-T-ELSIF提供了一種方便的檢查幾種替代方案的方法。對IF條件進行連續測試直到找到第一個IF條件為止。然後執行關聯的語句,之後控制在結束if之後傳遞給下一個語句。(任何後續的if條件未被測試)如果沒有IF條件是真的,則執行另一個塊(如果有的話)。

IF boolean-expression THEN

statements

[ ELSIF boolean-expression THEN

statements

[ ELSIF boolean-expression THEN

statements

...]]

[ ELSE

statements ]

END IF;

 

 

4. CASE

簡單的CASE形式提供了基於運算元相等的條件執行。搜尋表示式被計算(一次),並依次與WHEN子句中的每個表示式進行比較。如果找到匹配,則執行相應的語句,然後控制傳遞到END CASE之後的下一個語句。如果沒有找到匹配,則執行ELSE語句;但是如果不存在ELSE,則引發CASE_NOT_FOUND異常。

CASE search-expression

WHEN expression [, expression [ ... ]] THEN

statements

[ WHEN expression [, expression [ ... ]] THEN

statements

... ]

[ ELSE

statements ]

END CASE;

 

 

5. Searched CASE

CASE的搜尋形式基於布林表示式的真實性提供有條件的執行。每個子句的布林表示式依次進行評估,直到找到一個正確的表示式。然後執行相應的語句,然後控制在結束情況後傳遞給下一個語句。(當表示式未被計算時)。如果沒有找到真正的結果,則執行ELSE語句;但是如果不存在其他語句,則引發一個CaseSoNoSyDebug異常。

CASE

WHEN boolean-expression THEN

statements

[ WHEN boolean-expression THEN

statements

... ]

[ ELSE

statements ]

END CASE;

 

 

 

1. LOOP

迴圈定義一個無條件迴圈,該迴圈無限期地重複,直到退出或返回語句終止為止。巢狀迴圈中的EXIT和CONTINUE語句可以使用可選的標籤來指定這些語句引用哪個迴圈。

[ <<label>> ]

LOOP

statements

END LOOP [ label ];

 

 

2. EXIT

如果沒有給出標籤,則最內層迴圈被終止,接下來執行結束語句迴圈語句。如果給出標籤,它必須是巢狀迴圈或塊的當前或某個外部級別的標籤。然後,終止迴圈或塊,並在迴圈/塊的相應端之後繼續進行語句控制。

如果指定了,則只有在布林表示式為真時才出現迴圈退出。否則,控制元件傳遞到退出後的語句。

退出可用於所有型別的迴圈;它不限於使用無條件迴圈。

當與開始塊一起使用時,Exchange將控制元件傳遞給塊結束後的下一個語句。注意,必須為此使用標籤;未標記的退出永遠不會被認為與開始塊匹配。(這是PostgreSQL的前8個版本的更改,這將允許未標記的退出與開始塊匹配)。

EXIT [ label ] [ WHEN boolean-expression ];

 

Examples:

LOOP

-- some computations

IF count > 0 THEN

EXIT; -- exit loop

END IF;

END LOOP;

 

LOOP

-- some computations

EXIT WHEN count > 0; -- same result as previous example

END LOOP;

 

<<ablock>>

BEGIN

-- some computations

IF stocks > 100000 THEN

EXIT ablock; -- causes exit from the BEGIN block

END IF;

-- computations here will be skipped when stocks > 100000

END;

 

 

 

3. CONTINUE

如果沒有給出標籤,最內層迴圈的下一次迭代就開始了。也就是說,跳過迴圈主體中剩餘的所有語句,並且控制返回到迴圈控制表示式(如果有的話)以確定是否需要另一個迴圈迭代。如果存在標籤,則它指定將繼續執行的迴圈的標籤。

如果指定了,則只在布林表示式為真時才開始迴圈的下一次迭代。否則,控制元件在繼續後傳遞給語句。

繼續可用於所有型別的迴圈;它不限於使用無條件迴圈。

CONTINUE [ label ] [ WHEN boolean-expression ];

 

Examples:

LOOP

-- some computations

EXIT WHEN count > 100;

CONTINUE WHEN count < 50;

-- some computations for count IN [50 .. 100]

END LOOP;

 

 

4. WHILE

只要布林表示式求值為true,while語句就重複一系列語句。在迴圈體的每個條目之前檢查表示式。

[ <<label>> ]

WHILE boolean-expression LOOP

statements

END LOOP [ label ];

 

Example:

WHILE amount_owed > 0 AND gift_certificate_balance > 0 LOOP

-- some computations here

END LOOP;

 

WHILE NOT done LOOP

-- some computations here

END LOOP;

 

 

5. FOR (Integer Variant)

這種形式的FOR建立一個遍歷整數值範圍的迴圈。變數名自動定義為型別整數,並且只存在於迴圈中(在迴圈中忽略變數名的任何現有定義)。兩個表示式給出下限和上界的範圍時,一旦進入迴圈進行評估。如果BY子句沒有指定,迭代步驟是1,否則它是BY子句中指定的值,在迴圈條目中再次計算一次。如果指定反向,則在每次迭代之後減去步驟值,而不是新增。

[ <<label>> ]

FOR name IN [ REVERSE ] expression .. expression [ BY expression ] LOOP

statements

END LOOP [ label ];

 

 

Examples

FOR i IN 1..10 LOOP

-- i will take on the values 1,2,3,4,5,6,7,8,9,10 within the loop

END LOOP;

 

FOR i IN REVERSE 10..1 LOOP

-- i will take on the values 10,9,8,7,6,5,4,3,2,1 within the loop

END LOOP;

 

FOR i IN REVERSE 10..1 BY 2 LOOP

-- i will take on the values 10,8,6,4,2 within the loop

END LOOP;

 

 

 

1. Looping Through Query Results

如果迴圈由EXIT語句終止,則最後一個分配的行值仍然可以在迴圈之後訪問。

此類FOR語句中使用的查詢可以是向呼叫者返回行的任何SQL命令:SELECT是最常見的情況,但是您也可以使用INSERT、UPDATE或DELETE以及RETURNING子句。一些實用命令,如解釋也會起作用。

[ <<label>> ]

FOR target IN query LOOP

statements

END LOOP [ label ];

 

[ <<label>> ]

FOR target IN EXECUTE text_expression [ USING expression [, ... ] ] LOOP

statements

END LOOP [ label ];

 

這與前面的表單類似,只是查詢結果被指定為字串表示式,在FOR迴圈的每個條目上計算並重新命名該表示式。這允許程式設計師選擇預先計劃的查詢的速度或動態查詢的靈活性,就像使用普通的EXECUTE語句一樣。與執行一樣,引數值可以通過使用方式插入到動態命令中。

 

2. Looping Through Arrays

FOREACH迴圈非常類似於FOR迴圈,但是它不是遍歷SQL查詢返回的行,而是遍歷陣列值的元素。(通常,FOREACH用於迴圈複合值表示式的元件;將來可以新增除陣列之外的用於迴圈複合的變體。)

[ <<label>> ]

FOREACH target [ SLICE number ] IN ARRAY expression LOOP

statements

END LOOP [ label ];

如果沒有SLICE,或者如果指定了SLICE 0,迴圈迭代通過計算表示式生成的陣列的各個元素。目標變數按順序分配每個元素值,並且為每個元素執行迴圈體。

不管陣列維數的多少,都以儲存順序訪問元素。雖然目標通常只是單個變數,但是當迴圈遍歷複合值(記錄)陣列時,它可以是變數列表。在這種情況下,對於每個陣列元素,變數是從複合值的連續列分配的。

使用正向切片值,FOREACH迭代陣列的切片而不是單個元素。切片值必須是不大於陣列維數的整數常量。目標變數必須是陣列,並且它接收陣列值的連續切片,其中每個切片具有SLICE指定的維度數。這裡是一個迭代通過一維切片的例子:

 

 

3. Trapping Errors

預設情況下,在PL/pgSQL函式中發生的任何錯誤都會中止該函式的執行,實際上也會中止周圍事務的執行。通過使用帶有異常子句的開始塊,可以捕獲錯誤並從中恢復錯誤。

[ <<label>> ]

[ DECLARE

declarations ]

BEGIN

statements

EXCEPTION

WHEN condition [ OR condition ... ] THEN

handler_statements

[ WHEN condition [ OR condition ... ] THEN

handler_statements

... ]

END;

如果沒有發生錯誤,則這種形式的塊僅執行所有語句,然後控制傳遞到END之後的下一個語句。但是,如果在語句中發生錯誤,則放棄對語句的進一步處理,並將控制傳遞給EXCEPTION列表。在列表中搜索與發生的錯誤匹配的第一條件。如果找到匹配項,則執行相應的handler_statements,然後控制在結束後傳遞到下一個語句。如果沒有找到匹配,錯誤就傳播出去,好像EXCEPTION子句根本不存在:錯誤可以由帶有EXCEPTION的封閉塊捕獲,或者如果沒有,則中斷函式的處理。

條件名稱可以是附錄A中顯示的任何一個。類別名稱匹配其類別內的任何錯誤。除了QUERY_CANCELED和ASSERT_FAILURE之外,其他條件都匹配其他錯誤型別。(可以通過名稱捕獲這兩種錯誤型別是可能的,但往往不明智。)條件名稱不是區分大小寫的。此外,錯誤條件可以由SQLSTATE程式碼指定。

如果在所選的handler_statements中發生新錯誤,則此EXCEPTION子句無法捕獲該錯誤,但會傳播出去。周圍的例外條款可以抓住它。

當EXCEPTION子句捕獲錯誤時,PL/pgSQL函式的本地變數與發生錯誤時保持原樣,但是回滾塊中對持久資料庫狀態的所有更改。

 

異常處理程式經常需要識別發生的特定錯誤。有兩種方法可以獲得關於PL/pgSQL中當前異常的資訊:特殊變數和GET STACKED DIAGNOSTICS命令。

在異常處理程式中,特殊變數SQLSTATE包含與引發的異常對應的錯誤程式碼(可能的錯誤程式碼列表參見表A.1)。特殊變數SqLSRM包含與異常相關聯的錯誤訊息。這些變數在異常處理程式之外是未定義的。

在異常處理程式中,還可以通過使用GET STACKED DIAGNOSTICS命令檢索關於當前異常的資訊。

每個項是一個關鍵字,標識要分配給指定變數(它應該是接收該變數的正確資料型別)的狀態值。

Error Diagnostics Items

Name

Type

Description

RETURNED_SQLSTATE

text

the SQLSTATE error code of the exception

COLUMN_NAME

text

the name of the column related to exception

CONSTRAINT_NAME

text

the name of the constraint related to exception

PG_DATATYPE_NAME

text

the name of the data type related to exception

MESSAGE_TEXT

text

the text of the exception's primary message

TABLE_NAME

text

the name of the table related to exception

SCHEMA_NAME

text

the name of the schema related to exception

PG_EXCEPTION_DETAIL

text

the text of the exception's detail message, if any

PG_EXCEPTION_HINT

text

the text of the exception's hint message, if any

PG_EXCEPTION_CONTEXT

text

line(s) of text describing the call stack at the time of the exception

 

 

4. Obtaining Execution Location Information

GET DIAGNOSTICS命令檢索關於當前執行狀態的資訊。它的PG_CONTEXT狀態項對於識別當前執行位置是有用的。PG_CONTEXT返回一個文字字串,其中包含描述呼叫堆疊的文字行。第一行是指當前函式,當前正在執行GET DIAGNOSTICS 命令。第二個和任何後續行引用呼叫棧上的呼叫函式。

 

GET STACKED DIAGNOSTICS ... PG_EXCEPTION_CONTEXT 返回相同型別的堆疊跟蹤,但是描述檢測到錯誤的位置,而不是當前位置。