PostgreSQL使用select into target時有無STRICT關鍵字的區別
摘自官方文檔http://www.postgres.cn/docs/11/plpgsql-statements.html
43.5.3. 執行一個有單一行結果的查詢
一個產生單一行(可能有多個列)的 SQL 命令的結果可以被賦值給一個記錄變量、行類型變量或標量變量列表。這通過書寫基礎 SQL 命令並增加一個INTO子句來達成。例如:
SELECT select_expressions INTO [STRICT] target FROM ...;
INSERT ... RETURNING expressions INTO [STRICT] target; UPDATE ... RETURNING expressions INTO [STRICT] target; DELETE ... RETURNING expressions INTO [STRICT] target;
其中target可以是一個記錄變量、一個行變量或一個有逗號分隔的簡單變量和記錄/行域列表。PL/pgSQL變量將被替換到該查詢的剩余部分中,並且計划會被緩存,正如之前描述的對不返回行的命令所做的。這對SELECT、帶有RETURNING的INSERT/UPDATE/DELETE以及返回行集結果的工具命令(例如EXPLAIN)。除了INTO子句,SQL 命令和它在PL/pgSQL之外的寫法一樣。
提示
注意帶INTO的SELECT的這種解釋和PostgreSQL常規的SELECT INTO命令有很大的不同,后者的INTO目標是一個新創建的表。如果你想要在一個PL/pgSQL函數中從一個SELECT的結果創建一個表,請使用語法CREATE TABLE ... AS SELECT。
如果一行或一個變量列表被用作目標,該查詢的結果列必須完全匹配該結果的結構,包括數量和數據類型,否則會發生一個運行時錯誤。當一個記錄變量是目標時,它會自動地把自身配置成查詢結果列組成的行類型。
INTO子句幾乎可以出現在 SQL 命令中的任何位置。通常它被寫成剛好在SELECT命令中的select_expressions列表之前或之后,或者在其他命令類型的命令最后。我們推薦你遵循這種慣例,以防PL/pgSQL的解析器在未來的版本中變得更嚴格。
如果STRICT沒有在INTO子句中被指定,那么target將被設置為該查詢返回的第一個行,或者在該查詢不返回行時設置為空(注意除非使用了ORDER BY,否則“第一行”的界定並不清楚)。第一行之后的任何結果行都會被拋棄。你可以檢查特殊的FOUND變量(見第 43.5.5 節)來確定是否返回了一行:
SELECT * INTO myrec FROM emp WHERE empname = myname;
IF NOT FOUND THEN
RAISE EXCEPTION 'employee % not found', myname;
END IF;
如果指定了STRICT選項,該查詢必須剛好返回一行或者將會報告一個運行時錯誤,該錯誤可能是NO_DATA_FOUND(沒有行)或TOO_MANY_ROWS(多於一行)。如果你希望捕捉該錯誤,可以使用一個異常塊,例如:
BEGIN
SELECT * INTO STRICT myrec FROM emp WHERE empname = myname;
EXCEPTION
WHEN NO_DATA_FOUND THEN
RAISE EXCEPTION 'employee % not found', myname;
WHEN TOO_MANY_ROWS THEN
RAISE EXCEPTION 'employee % not unique', myname;
END;
成功執行一個帶STRICT的命令總是會將FOUND置為真。
對於帶有RETURNING的INSERT/UPDATE/DELETE,即使沒有指定STRICT,PL/pgSQL也會針對多於一個返回行的情況報告一個錯誤。這是因為沒有類似於ORDER BY的選項可以用來決定應該返回哪個被影響的行。
如果為該函數啟用了If print_strict_params,那么當因為 STRICT的要求沒有被滿足而拋出一個錯誤時,該錯誤消息 的DETAIL將包括傳遞給該查詢的參數信息。可以通過設置 plpgsql.print_strict_params為所有函數更改 print_strict_params設置,但是只有修改后被編譯的函數 才會生效。也可以使用一個編譯器選項來為一個函數啟用它,例如:
CREATE FUNCTION get_userid(username text) RETURNS int
AS $$
#print_strict_params on
DECLARE
userid int;
BEGIN
SELECT users.userid INTO STRICT userid
FROM users WHERE users.username = get_userid.username;
RETURN userid;
END
$$ LANGUAGE plpgsql;
失敗時,這個函數會產生一個這樣的錯誤消息
ERROR: query returned no rows DETAIL: parameters: $1 = 'nosuchuser' CONTEXT: PL/pgSQL function get_userid(text) line 6 at SQL statement
注意
STRICT選項匹配 Oracle PL/SQL 的SELECT INTO和相關語句的行為。
對於要處理來自於一個 SQL 查詢的結果行的情況,請見第 43.6.6 節。
