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 初始條件,或使用非 strict 轉換函式。
如果狀態轉換函式不是 strict,則會在每個輸入列無條件調用它,並且它必須自行處理 null 輸入和 null 狀態值。 這讓彙總函式的作者可以完全控制彙總對 null 值的處理。
如果最終函式宣告為 “strict”,則當結束狀態值為 null 時,將不會調用它;而是會自動傳回 null 結果。(當然,這只是 strict 函式的正常行為。) 在任何情況下,最終函式都可以選擇傳回 null 值。 例如,當 avg
的最終函式看到輸入列的數量為零時,會傳回 null。
有時候,宣告最終函數不僅接收狀態值,還接收對應於聚集輸入值的額外參數會很有用。這樣做的主要原因是,如果最終函數是多型的,且狀態值的資料類型不足以確定結果類型。這些額外參數總是作為 NULL 傳遞(因此,當使用 FINALFUNC_EXTRA
選項時,最終函數不能是 strict),但它們仍然是有效的參數。例如,最終函數可以使用 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;
進一步的假設是,聚集忽略空輸入,並且當且僅當沒有非空輸入時,它才傳回空結果。通常,資料類型的 <
運算子是 MIN
的正確排序運算子,而 >
是 MAX
的正確排序運算子。請注意,除非指定的運算子是 B 樹索引運算子類別的「小於」或「大於」策略成員,否則優化永遠不會實際生效。
為了能夠建立聚集函數,您必須具有對引數類型、狀態類型和傳回類型的 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
表示不是;其他兩個值表示它可能會更改轉換狀態值。 有關更多詳細訊息,請參閱下面的註解。預設值為 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
不得為 strict。在這種情況下,combinefunc
必須確保正確處理 null 狀態,並且傳回的狀態已正確儲存在彙總記憶體內容中。
serialfunc
只有當彙總函數具有 serialfunc
函數時,其 state_data_type
為 internal
才能參與平行彙總,該函數必須將彙總狀態序列化為 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
相同的引數和結果類型,但它用於從當前彙總狀態中移除值,而不是將值新增到其中。 反向轉換函數必須具有與前向狀態轉換函數相同的 strictness 屬性。
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 標準未提供使用者定義的聚合函數。
如果您在文件中發現任何不正確、與特定功能的經驗不符或需要進一步澄清的地方,請使用此表格來報告文件問題。