CREATE AGGREGATE — 定義一個新的聚合函式
CREATE [ OR REPLACE ] AGGREGATEname
( [argmode
] [argname
]arg_data_type
[ , ... ] ) ( SFUNC =sfunc
, STYPE =state_data_type
[ , SSPACE =state_data_size
] [ , FINALFUNC =ffunc
] [ , FINALFUNC_EXTRA ] [ , FINALFUNC_MODIFY = { READ_ONLY | SHAREABLE | READ_WRITE } ] [ , COMBINEFUNC =combinefunc
] [ , SERIALFUNC =serialfunc
] [ , DESERIALFUNC =deserialfunc
] [ , INITCOND =initial_condition
] [ , MSFUNC =msfunc
] [ , MINVFUNC =minvfunc
] [ , MSTYPE =mstate_data_type
] [ , MSSPACE =mstate_data_size
] [ , MFINALFUNC =mffunc
] [ , MFINALFUNC_EXTRA ] [ , MFINALFUNC_MODIFY = { READ_ONLY | SHAREABLE | READ_WRITE } ] [ , MINITCOND =minitial_condition
] [ , SORTOP =sort_operator
] [ , PARALLEL = { SAFE | RESTRICTED | UNSAFE } ] ) CREATE [ OR REPLACE ] AGGREGATEname
( [ [argmode
] [argname
]arg_data_type
[ , ... ] ] ORDER BY [argmode
] [argname
]arg_data_type
[ , ... ] ) ( SFUNC =sfunc
, STYPE =state_data_type
[ , SSPACE =state_data_size
] [ , FINALFUNC =ffunc
] [ , FINALFUNC_EXTRA ] [ , FINALFUNC_MODIFY = { READ_ONLY | SHAREABLE | READ_WRITE } ] [ , INITCOND =initial_condition
] [ , PARALLEL = { SAFE | RESTRICTED | UNSAFE } ] [ , HYPOTHETICAL ] ) or the old syntax CREATE [ OR REPLACE ] AGGREGATEname
( BASETYPE =base_type
, SFUNC =sfunc
, STYPE =state_data_type
[ , SSPACE =state_data_size
] [ , FINALFUNC =ffunc
] [ , FINALFUNC_EXTRA ] [ , FINALFUNC_MODIFY = { READ_ONLY | SHAREABLE | READ_WRITE } ] [ , COMBINEFUNC =combinefunc
] [ , SERIALFUNC =serialfunc
] [ , DESERIALFUNC =deserialfunc
] [ , INITCOND =initial_condition
] [ , MSFUNC =msfunc
] [ , MINVFUNC =minvfunc
] [ , MSTYPE =mstate_data_type
] [ , MSSPACE =mstate_data_size
] [ , MFINALFUNC =mffunc
] [ , MFINALFUNC_EXTRA ] [ , MFINALFUNC_MODIFY = { READ_ONLY | SHAREABLE | READ_WRITE } ] [ , MINITCOND =minitial_condition
] [ , SORTOP =sort_operator
] )
CREATE AGGREGATE
定義一個新的聚合函式。 CREATE OR REPLACE AGGREGATE
會定義一個新的聚合函式或替換一個已有的定義。一些基本且常用的聚合函式已包含在發行版中;它們在 第 9.21 節 中有文件說明。如果定義了新型別或需要一個尚未提供的聚合函式,則可以使用 CREATE AGGREGATE
來提供所需的功能。
替換現有定義時,不能更改引數型別、結果型別和直接引數的數量。此外,新定義必須與舊定義屬於同一型別(普通聚合、有序集聚合或假設集聚合)。
如果給定了模式名(例如,CREATE AGGREGATE myschema.myagg ...
),則該聚合函式將在指定的模式中建立。否則,它將在當前模式中建立。
聚合函式由其名稱和輸入資料型別(或型別)標識。同一模式下的兩個聚合函式可以具有相同的名稱,只要它們操作的輸入型別不同。聚合函式的名稱和輸入資料型別(或型別)也必須與同一模式下所有普通函式的名稱和輸入資料型別(或型別)不同。此行為與普通函式名稱的過載(參見 CREATE FUNCTION)相同。
一個簡單的聚合函式由一個或兩個普通函式構成:一個狀態轉換函式 sfunc
,以及一個可選的最終計算函式 ffunc
。它們的使用方式如下:
sfunc
( internal-state, next-data-values ) ---> next-internal-stateffunc
( internal-state ) ---> aggregate-value
PostgreSQL 建立一個 stype
型別的資料的臨時變數,用於儲存聚合的當前內部狀態。對於每一行輸入,都會計算聚合引數值,然後呼叫狀態轉換函式,傳入當前狀態值和新的引數值,以計算一個新的內部狀態值。所有行處理完畢後,將呼叫一次最終函式來計算聚合的返回值。如果沒有最終函式,則直接返回最終狀態值。
聚合函式可以提供一個初始條件,即內部狀態值的初始值。這將在資料庫中指定並存儲為 text
型別的值,但它必須是狀態值資料型別的常量的有效外部表示。如果未提供,則狀態值將從 null 開始。
如果狀態轉換函式被宣告為 “strict”(嚴格),則不能使用 null 輸入呼叫它。使用這種轉換函式時,聚合執行行為如下:帶有任何 null 輸入值的行將被忽略(函式不會被呼叫,並且會保留先前的值)。如果初始狀態值為 null,則在所有輸入值都非 null 的第一行,第一個引數值將替換狀態值,並且在每個後續所有輸入值都非 null 的行上呼叫轉換函式。這對於實現像 max
這樣的聚合非常有用。請注意,只有當 state_data_type
與第一個 arg_data_type
相同時,才可用此行為。當這些型別不同時,您必須提供一個非 null 的初始條件或使用一個非嚴格的轉換函式。
如果狀態轉換函式不是嚴格的,則它將在每行輸入時無條件呼叫,並且必須自行處理 null 輸入和 null 狀態值。這允許聚合作者完全控制聚合對 null 值的處理。
如果最終函式被宣告為 “strict”(嚴格),則當最終狀態值為 null 時它不會被呼叫;而是會自動返回一個 null 結果。(當然,這只是嚴格函式的正常行為。)無論如何,最終函式可以選擇返回 null 值。例如,avg
的最終函式在看到零輸入行時返回 null。
有時宣告最終函式不僅接受狀態值,還接受與聚合輸入值對應的額外引數會很有用。這樣做的主要原因是,如果最終函式是多型的,並且狀態值的資料型別不足以確定結果型別。這些額外引數始終作為 NULL 傳遞(因此,當使用 FINALFUNC_EXTRA
選項時,最終函式不能是嚴格的),但儘管如此,它們仍然是有效的引數。例如,最終函式可以使用 get_fn_expr_argtype
來識別當前呼叫中的實際引數型別。
聚合可以可選地支援 移動聚合模式,如 第 36.12.1 節 中所述。這需要指定 MSFUNC
、MINVFUNC
和 MSTYPE
引數,以及可選的 MSSPACE
、MFINALFUNC
、MFINALFUNC_EXTRA
、MFINALFUNC_MODIFY
和 MINITCOND
引數。除了 MINVFUNC
之外,這些引數的工作方式與不帶 M
的相應簡單聚合引數相同;它們定義了一個包含反向轉換函式的聚合的單獨實現。
引數列表中的 ORDER BY
語法建立了一種特殊型別的聚合,稱為 有序集聚合;或者如果指定了 HYPOTHETICAL
,則建立 假設集聚合。這些聚合以依賴於順序的方式操作一組排序值,因此指定輸入排序順序是呼叫中的一個重要部分。此外,它們可以具有 直接 引數,這些引數是每個聚合而不是每個輸入行僅評估一次的引數。假設集聚合是有序集聚合的一個子類,其中一些直接引數在數量和資料型別上必須與聚合引數列匹配。這允許這些直接引數的值作為額外的 “假設” 行新增到聚合輸入行的集合中。
聚合可以可選地支援 部分聚合,如 第 36.12.4 節 中所述。這需要指定 COMBINEFUNC
引數。如果 state_data_type
是 internal
,那麼通常也提供 SERIALFUNC
和 DESERIALFUNC
引數,以便進行並行聚合。請注意,為了啟用並行聚合,聚合還必須標記為 PARALLEL SAFE
。
行為類似於 MIN
或 MAX
的聚合有時可以透過檢視索引而不是掃描每個輸入行來進行最佳化。如果該聚合可以這樣最佳化,則透過指定一個 排序運算子 來指示。基本要求是聚合必須產生由運算子誘導的排序中的第一個元素;換句話說:
SELECT agg(col) FROM tab;
必須等價於
SELECT col FROM tab ORDER BY col USING sortop LIMIT 1;
進一步的假設是,聚合忽略 null 輸入,並且當且僅當沒有非 null 輸入時才返回 null 結果。通常,資料型別的 <
運算子是 MIN
的正確排序運算子,而 >
是 MAX
的正確排序運算子。請注意,除非指定的運算子是 B-tree 索引運算子類的 “小於” 或 “大於” 策略成員,否則最佳化將永遠不會真正生效。
要建立聚合函式,您必須對引數型別、狀態型別(或型別)和返回型別具有 USAGE
許可權,以及對支援函式具有 EXECUTE
許可權。
name
要建立的聚合函式的名稱(可以選擇模式限定)。
argmode
引數的模式: IN
或 VARIADIC
。(聚合函式不支援 OUT
引數。)如果省略,則預設為 IN
。只有最後一個引數可以標記為 VARIADIC
。
argname
引數的名稱。目前這僅對文件目的有用。如果省略,該引數沒有名稱。
arg_data_type
此聚合函式操作的輸入資料型別。要建立一個零引數聚合函式,請在引數規範列表處寫 *
。(例如,這樣的聚合是 count(*)
。)
base_type
在 CREATE AGGREGATE
的舊語法中,輸入資料型別由 basetype
引數指定,而不是寫在聚合名稱旁邊。請注意,此語法只允許一個輸入引數。要使用此語法定義零引數聚合函式,請將 basetype
指定為 "ANY"
(而不是 *
)。有序集聚合不能使用舊語法定義。
sfunc
每個輸入行都要呼叫的狀態轉換函式的名稱。對於一個正常的 N
-引數聚合函式,sfunc
必須接受 N
+1 個引數,第一個引數是 state_data_type
型別,其餘引數與聚合宣告的輸入資料型別(或型別)匹配。該函式必須返回 state_data_type
型別的值。該函式接收當前狀態值和當前輸入資料值(或值),並返回下一個狀態值。
對於有序集(包括假設集)聚合,狀態轉換函式僅接收當前狀態值和聚合引數,而不接收直接引數。否則,它與普通情況相同。
state_data_type
聚合狀態值的的資料型別。
state_data_size
聚合狀態值的近似平均大小(以位元組為單位)。如果省略此引數或其值為零,則基於 state_data_type
進行預設估算。規劃器使用此值來估算分組聚合查詢所需的記憶體。
ffunc
遍歷所有輸入行後,用於計算聚合結果的最終函式的名稱。對於普通聚合,該函式必須接受一個 state_data_type
型別的引數。聚合的返回資料型別定義為該函式的返回型別。如果未指定 ffunc
,則使用最終狀態值作為聚合的結果,返回型別為 state_data_type
。
對於有序集(包括假設集)聚合,最終函式不僅接收最終狀態值,還接收所有直接引數的值。
如果指定了 FINALFUNC_EXTRA
,則除了最終狀態值和任何直接引數外,最終函式還會接收對應於聚合的常規(聚合)引數的額外 NULL 值。這主要用於允許在定義多型聚合時正確解析聚合結果型別。
FINALFUNC_MODIFY
= { READ_ONLY
| SHAREABLE
| READ_WRITE
}此選項指定最終函式是否為不修改其引數的純函式。READ_ONLY
表示不修改;其他兩個值表示它可以更改轉換狀態值。請參閱下面的 Notes 以獲取更多詳細資訊。預設為 READ_ONLY
,但對於有序集聚合,預設值為 READ_WRITE
。
combinefunc
可以有選擇地指定 combinefunc
函式,以允許聚合函式支援部分聚合。如果提供了 combinefunc
,則必須組合兩個 state_data_type
值,每個值包含對某些輸入值子集進行聚合的結果,以產生一個新的 state_data_type
值,該值表示對兩個輸入集進行聚合的結果。此函式可以被視為一個 sfunc
,但它不是作用於單個輸入行並將其新增到執行聚合狀態,而是將另一個聚合狀態新增到執行狀態。
combinefunc
必須宣告為接受 state_data_type
的兩個引數並返回 state_data_type
型別的值。可選地,此函式可以是 “strict”(嚴格)的。在這種情況下,當任一輸入狀態為 null 時,函式將不會被呼叫;另一個狀態將作為正確的結果。
對於 state_data_type
為 internal
的聚合函式,combinefunc
不能是嚴格的。在這種情況下,combinefunc
必須確保正確處理 null 狀態,並確保返回的狀態正確儲存在聚合記憶體上下文中。
serialfunc
狀態資料型別為 internal
的聚合函式,只有在具有 serialfunc
函式時才能參與並行聚合。該函式必須將聚合狀態序列化為 bytea
值,以便傳輸到另一個程序。此函式必須接受一個 internal
型別的引數並返回 bytea
型別。還需要一個相應的 deserialfunc
。
deserialfunc
將先前序列化的聚合狀態反序列化回 state_data_type
。此函式必須接受 bytea
和 internal
兩種型別的引數,併產生 internal
型別的結果。(注意:第二個 internal
引數未使用,但出於型別安全原因而必需。)
initial_condition
狀態值的初始設定。這必須是一個字串常量,格式符合 state_data_type
的資料型別。如果未指定,則狀態值從 null 開始。
msfunc
在移動聚合模式下,對於每一行輸入都要呼叫的前向狀態轉換函式。這與常規轉換函式完全相同,只是其第一個引數和結果是 mstate_data_type
型別,這可能與 state_data_type
不同。
minvfunc
在移動聚合模式下使用的反向狀態轉換函式的名稱。此函式具有與 msfunc
相同的引數和結果型別,但它用於從當前聚合狀態中移除一個值,而不是新增一個值。反向轉換函式必須具有與前向狀態轉換函式相同的嚴格性屬性。
mstate_data_type
在使用移動聚合模式時,聚合狀態值的型別。
mstate_data_size
在使用移動聚合模式時,聚合狀態值的近似平均大小(以位元組為單位)。此功能與 state_data_size
相同。
mffunc
在移動聚合模式下,遍歷所有輸入行後,用於計算聚合結果的最終函式的名稱。這與 ffunc
的工作方式相同,只是其第一個引數的型別是 mstate_data_type
,並且額外的虛擬引數透過編寫 MFINALFUNC_EXTRA
來指定。由 mffunc
或 mstate_data_type
確定的聚合結果型別必須與聚合的常規實現所確定的型別匹配。
MFINALFUNC_MODIFY
= { READ_ONLY
| SHAREABLE
| READ_WRITE
}此選項類似於 FINALFUNC_MODIFY
,但它描述了移動聚合最終函式的行為。
minitial_condition
在使用移動聚合模式時,狀態值的初始設定。此功能與 initial_condition
相同。
sort_operator
用於 MIN
或 MAX
類聚合的相關排序運算子。這只是一個運算子名稱(可能已模式限定)。假定該運算子具有與聚合相同的輸入資料型別(該聚合必須是單引數的普通聚合)。
PARALLEL =
{ SAFE
| RESTRICTED
| UNSAFE
}PARALLEL SAFE
、PARALLEL RESTRICTED
和 PARALLEL UNSAFE
的含義與 CREATE FUNCTION
中的含義相同。如果聚合標記為 PARALLEL UNSAFE
(這是預設值!)或 PARALLEL RESTRICTED
,則該聚合不會被考慮進行並行化。請注意,規劃器不會檢查聚合支援函式的並行安全標記,只檢查聚合本身的標記。
HYPOTHETICAL
僅對有序集聚合,此標誌指定聚合引數將根據假設集聚合的要求進行處理:也就是說,最後幾個直接引數必須與聚合的(WITHIN GROUP
)引數的資料型別匹配。HYPOTHETICAL
標誌對執行時行為沒有影響,隻影響聚合引數的資料型別和排序規則的解析。
CREATE AGGREGATE
的引數可以按任何順序編寫,不一定按照上面示例的順序。
在指定支援函式名稱的引數中,如果需要,可以寫模式名,例如 SFUNC = public.sum
。但是,不要在那裡寫引數型別 — 支援函式的引數型別是從其他引數確定的。
通常,PostgreSQL 函式被期望為不修改輸入值的真函式。然而,聚合轉換函式,在聚合的上下文中使用的,允許作弊並就地修改其轉換狀態引數。與每次都製作一個轉換狀態的副本相比,這可以帶來顯著的效能優勢。
同樣,雖然通常期望聚合最終函式不修改其輸入值,但有時避免修改轉換狀態引數是不可行的。此類行為必須使用 FINALFUNC_MODIFY
引數宣告。READ_WRITE
值表示最終函式以未指定的方式修改轉換狀態。此值會阻止將聚合用作視窗函式,也會阻止合併對於具有相同輸入值和轉換函式的聚合呼叫的轉換狀態。SHAREABLE
值表示轉換函式不能在最終函式之後應用,但可以對最終轉換狀態值執行多個最終函式呼叫。此值會阻止將聚合用作視窗函式,但允許合併轉換狀態。(也就是說,這裡感興趣的最佳化不是重複應用相同的最終函式,而是對相同的最終轉換狀態值應用不同的最終函式。只要沒有任何最終函式被標記為 READ_WRITE
,就允許這樣做。)
如果聚合支援移動聚合模式,當聚合作為具有移動幀開始的視窗函式使用時(即,幀開始模式不是 UNBOUNDED PRECEDING
),這將提高計算效率。概念上,前向轉換函式在值進入視窗幀底部時將輸入值新增到聚合狀態,反向轉換函式在值離開頂部幀時將其移除。因此,當移除值時,它們總是以新增的順序移除。每當呼叫反向轉換函式時,它將接收到最早新增但尚未移除的引數值(或值)。反向轉換函式可以假定,在移除最舊的行之後,當前狀態中至少會保留一行。(當不滿足此條件時,視窗函式機制將簡單地啟動一個新的聚合,而不是使用反向轉換函式。)
移動聚合模式的前向轉換函式不允許返回 NULL 作為新狀態值。如果反向轉換函式返回 NULL,這將被視為一個指示,表明反向函式無法撤銷此特定輸入的狀��計算,因此將從當前幀的起始位置重新計算聚合。此約定允許在某些不頻繁的、難以從執行狀態值中逆向計算的情況下使用移動聚合模式。
如果沒有提供移動聚合實現,聚合仍然可以與移動幀一起使用,但 PostgreSQL 將在幀的起始位置移動時重新計算整個聚合。請注意,無論聚合是否支援移動聚合模式,PostgreSQL 都可以處理移動幀的結束而無需重新計算;這是透過繼續將新值新增到聚合狀態來實現的。這就是為什麼將聚合用作視窗函式需要最終函式是隻讀的:它不得損壞聚合的狀態值,以便即使在為一個幀邊界集獲得聚合結果值後也可以繼續進行聚合。
有序集聚合的語法允許為最後一個直接引數和最後一個聚合的(WITHIN GROUP
)引數指定 VARIADIC
。然而,當前的實現對 VARIADIC
的使用有限制。首先,有序集聚合只能使用 VARIADIC "any"
,而不是其他可變引數陣列型別。其次,如果最後一個直接引數是 VARIADIC "any"
,則只能有一個聚合引數,並且它也必須是 VARIADIC "any"
。(在系統目錄中使用的方式中,這兩個引數合併為一個 VARIADIC "any"
專案,因為 pg_proc
無法表示函式有多個 VARIADIC
引數。)如果聚合是假設集聚合,則匹配 VARIADIC "any"
引數的直接引數是假設引數;任何前面的引數表示額外的直接引數,這些引數不必與聚合引數匹配。
目前,有序集聚合不需要支援移動聚合模式,因為它們不能用作視窗函式。
目前,有序集聚合不支援部分(包括並行)聚合。此外,對於包含 DISTINCT
或 ORDER BY
子句的聚合呼叫,它將永遠不會被使用,因為這些語義無法在部分聚合期間得到支援。
參見 第 36.12 節。
CREATE AGGREGATE
是 PostgreSQL 的語言擴充套件。SQL 標準不提供使用者定義聚合函式。
如果您在文件中看到任何不正確、與您對特定功能的經驗不符或需要進一步澄清的內容,請使用 此表單 來報告文件問題。