函數是作為表達式調用的獨立 SPL 程序。進行求值后,函數返回一個值,該值在該函數所嵌入的表達式中被替換。函數可以選擇以輸入參數的形式從調用程序獲取值。除了函數實際上本身返回值之外,函數還可以選擇以輸出參數的形式向調用方返回其他值。不過,在函數中使用輸出參數并不是提倡的編程做法。

CREATE FUNCTION 命令定義并命名一個將存儲在數據庫中的獨立函數。

如果包括 schema 名稱,則在指定 schema 中創建函數。否則在當前 schema 中創建。對于任何現有函數,如果與新函數在相同的 schema 中具有相同的輸入參數類型,則新函數名稱不能與現有函數名稱匹配。不過,具有不同輸入參數類型的函數可共用一個名稱(這稱為重載)。(函數重載是PolarDB PostgreSQL版(兼容Oracle)的一項功能,重載已存儲的獨立函數這一功能與 Oracle 數據庫不兼容。)

要更新現有函數的定義,請使用 CREATEOR REPLACE FUNCTION。無法以此方式更改函數的名稱或參數類型(如果您嘗試過此方式,實際上創建的是一個新的不同函數)。此外,CREATE OR REPLACE FUNCTION 不會讓您更改現有函數的返回類型。要更改現有函數的返回類型,您必須刪除并重新創建函數。此外,在使用 OUT 參數時,除非通過刪除函數,否則您不能更改任何 OUT 參數的類型。

CREATE [ OR REPLACE ] FUNCTION name [ (parameters) ]
  RETURN data_type
   [
          IMMUTABLE
        | STABLE
        | VOLATILE
        | DETERMINISTIC
        | [ NOT ] LEAKPROOF
        | CALLED ON NULL INPUT
        | RETURNS NULL ON NULL INPUT
        | STRICT
        | [ EXTERNAL ] SECURITY INVOKER
        | [ EXTERNAL ] SECURITY DEFINER
        | AUTHID DEFINER
        | AUTHID CURRENT_USER
        | PARALLEL { UNSAFE | RESTRICTED | SAFE }
        | COST execution_cost
        | ROWS result_rows
        | SET configuration_parameter
          { TO value | = value | FROM CURRENT }
   ...]
{ IS | AS }
    [ PRAGMA AUTONOMOUS_TRANSACTION; ]
    [ declarations ]
  BEGIN
    statements
  END [ name ];
參數說明
namename 是函數的標識符。
parametersparameters 是形參的列表。
data_typedata_type 是函數的 RETURN 語句所返回值的數據類型。
declarationsdeclarations 是變量、游標、類型或子程序聲明。如果包括子程序聲明,則它們必須在所有其他變量、游標和類型聲明之后。
statementsstatements 是 SPL 程序語句(BEGIN - END 塊可以包含 EXCEPTION 部分)。
IMMUTABLE

STABLE

VOLATILE

這些屬性將函數的行為通知給查詢優化器;您只能指定一個選項。VOLATILE 是默認行為。
  • IMMUTABLE 指示函數不能修改數據庫,并在提供相同參數值時始終會得到相同結果;它不執行數據庫查找,也不以其他方式使用其參數列表中不直接存在的信息。如果包括此子句,則使用全常量參數對函數的任意調用將立即替換為函數值。
  • STABLE 指示函數不能修改數據庫,并在單表掃描中,它將一致地為相同參數值返回同一結果,但其結果可能在 SQL 語句之間發生更改。對于依賴于數據庫查找、參數變量(例如當前時區)等的函數,這是合適的選擇。
  • VOLATILE 指示即使在單表掃描中函數值也可以更改,因此不能進行任何優化。請注意,任何具有負面影響的函數必須分類為易失性函數,即使其結果可預測性很好也是如此,這是為了防止調用由于優化而被去除。
DETERMINISTICDETERMINISTIC 是 IMMUTABLE 的同義詞。DETERMINISTIC 函數不能修改數據庫,并在提供相同參數值時始終會得到相同結果;它不執行數據庫查找,也不以其他方式使用其參數列表中不直接存在的信息。如果包括此子句,則使用全常量參數對函數的任意調用將立即替換為函數值。
[ NOT ] LEAKPROOFLEAKPROOF 函數沒有負面影響,也不會公開有關調用函數所用值的任何信息。
CALLED ON NULL INPUT

RETURNS NULL ON NULL INPUT

STRICT

  • CALLED ON NULL INPUT(默認值)指示當存儲過程的某些參數為 NULL 時,將正常調用該存儲過程。如果需要,作者需要負責檢查 NULL 值并做出適當的響應。
  • RETURNS NULL ON NULL INPUT 或 STRICT 指示只要存儲過程的任何參數為 NULL,該存儲過程就始終返回 NULL。如果指定了這些子句,則當存在 NULL 參數時,不會執行該存儲過程,而是自動假定為 NULL 結果。
[ EXTERNAL ] SECURITY DEFINERSECURITY DEFINER 指定函數將使用創建該函數的用戶的特權執行;這是默認值。為了符合 SQL 要求,允許使用關鍵字 EXTERNAL,但這是可選的。
[ EXTERNAL ] SECURITY INVOKERSECURITY INVOKER 子句指示函數將使用調用該函數的用戶的特權執行。為了符合 SQL 要求,允許使用關鍵字 EXTERNAL,但這是可選的。
AUTHID DEFINER

AUTHID CURRENT_USER

AUTHID DEFINER 子句是 [EXTERNAL] SECURITY DEFINER 的同義詞。如果省略 AUTHID 子句或者指定了 AUTHID DEFINER,則使用函數所有者的權限來確定對數據庫對象的訪問特權。

AUTHID CURRENT_USER 子句是 [EXTERNAL] SECURITY INVOKER 的同義詞。如果指定 AUTHID CURRENT_USER,則使用執行函數的當前用戶的權限來確定訪問特權。

PARALLEL { UNSAFE | RESTRICTED | SAFE }通過 PARALLEL 子句可以使用并行順序掃描(并行模式)。在查詢期間,相比串行順序掃描,并行順序掃描使用多個工作線程并行掃描一個關系。
  • 設置為 UNSAFE 時,函數不能以并行模式執行。SQL 語句中存在此類函數時,會強制執行串行執行計劃。如果省略 PARALLEL 子句,則這是默認設置。
  • 設置為 RESTRICTED 時,函數可以按并行模式執行,但執行限制為并行組中的前幾個。如果任何特定關系的限定條件具有存在并行限制的任何內容,則不會為并行執行選擇該關系。
  • 設置為 SAFE 時,函數可以按并行模式執行,沒有任何限制。
COST execution_costexecution_cost 是一個正數,給出函數的估計執行成本,單位為 cpu_operator_cost。如果函數返回一個集合,則這是每個返回行的成本。較大值會導致計劃程序嘗試避免超出必要的頻率來對函數求值。
ROWS result_rowsresult_rows 是一個正數,給出計劃程序預計函數返回的估計行數。只有當函數聲明為返回一個集合時,才允許使用此值。默認假定值為 1000 行。
SET configuration_parameter { TO value | = value | FROMCURRENT }SET 子句使指定的配置參數在進入函數時設置為指定值,然后在函數退出時恢復為其之前的值。SET FROM CURRENT 將會話的當前參數值保存為進入函數時要應用的值。

如果 SET 子句附加到函數,則在函數內針對相同變量執行 SET LOCAL 命令的效果僅限于該函數;函數退出時配置參數將恢復為之前的值。普通的 SET 命令(沒有 LOCAL)會重寫 SET 子句,與對之前 SET LOCAL 命令的操作很相似,此命令的效果在退出存儲過程后會保留,除非回滾當前事務。

PRAGMA AUTONOMOUS_TRANSACTIONPRAGMA AUTONOMOUS_TRANSACTION 是將函數設置為自治事務的指令。
說明 STRICT、LEAKPROOF、PARALLEL、COST、ROWS 和 SET 關鍵字可以為PolarDB PostgreSQL版(兼容Oracle)提供擴展功能,但 Oracle 不支持這些關鍵字。

示例

下面是一個不采用參數的簡單函數的示例。

CREATE OR REPLACE FUNCTION simple_function
    RETURN VARCHAR2
IS
BEGIN
    RETURN 'That''s All Folks!';
END simple_function;

以下函數采用兩個輸入參數。參數將在后面的章節中更詳細地講述。

CREATE OR REPLACE FUNCTION emp_comp (
    p_sal           NUMBER,
    p_comm          NUMBER
) RETURN NUMBER
IS
BEGIN
    RETURN (p_sal + NVL(p_comm, 0)) * 24;
END emp_comp;

以下示例演示了如何在函數聲明中使用 AUTHID CURRENT_USER 子句和 STRICT 關鍵字:

CREATE OR REPLACE FUNCTION dept_salaries(dept_id int) RETURN NUMBER
  STRICT
  AUTHID CURRENT_USER
BEGIN
  RETURN QUERY (SELECT sum(salary) FROM emp WHERE deptno = id);
END;

包括 STRICT 關鍵字以指示在傳遞的任意輸入參數為 NULL 時,服務器返回 NULL;如果傳遞了 NULL 值,則不執行函數。

dept_salaries 函數使用調用該函數的角色的特權執行。如果當前用戶沒有足夠的特權來執行查詢 emp 表的 SELECT 語句(以顯示員工工資),則函數將報告錯誤。要指示服務器使用與定義了函數的角色關聯的特權,可將 AUTHID CURRENT_USER 子句替換為 AUTHID DEFINER 子句。