PostgreSQL 允许对具备形参名的函数采用位置表示法(positional)或具名表示法(named)进行调用。对于拥有大量可选参数的复杂函数,具名表示法尤为实用,因为它使得形参与实参之间的绑定关系更加清晰可靠。在位置表示法中,实参必须严格按照函数声明中的参数顺序依次输入;而在具名表示法中,实参通过名称与形参精准对齐,书写顺序完全不受限制。关于函数实参类型推导的更多技术考量,参见 Section 10.3。
无论采用何种表示法,在函数声明中已经赋予了默认值的参数在调用时都可以完全省略。而在具名表示法中这一点更为灵活,你可以任意省略中间或末尾的任何具有默认值的参数;而位置表示法中参数仅支持自右向左依次省略。
PostgreSQL 还支持混合表示法(mixed),即将位置表示法与具名表示法结合使用。在此模式下,位置参数必须书写在最前端,具名参数排在其后。
我们通过以下函数定义演示这三种表示法的具体运用:
CREATE FUNCTION concat_lower_or_upper(a text, b text, uppercase boolean DEFAULT false)
RETURNS text
AS
$$
SELECT CASE
WHEN $3 THEN UPPER($1 || ' ' || $2)
ELSE LOWER($1 || ' ' || $2)
END;
$$
LANGUAGE SQL IMMUTABLE STRICT;
函数 concat_lower_or_upper 拥有两个强制必需参数 a 与 b,以及一个默认值为 false 的可选参数 uppercase。它会将输入的 a 与 b 拼接,并根据 uppercase 决定转为全大写还是全小写(函数定义的其余细节详见 Chapter 36)。
位置表示法是 PostgreSQL 传递函数实参的传统经典机制:
SELECT concat_lower_or_upper('Hello', 'World', true);
concat_lower_or_upper
-----------------------
HELLO WORLD
(1 row)
所有实参严格按序排列。再如省略可选参数的调用:
SELECT concat_lower_or_upper('Hello', 'World');
concat_lower_or_upper
-----------------------
hello world
(1 row)
此处省略了 uppercase,它自动获取默认值 false,输出全小写结果。位置表示法仅支持从最右侧起向前省略具有默认值的参数。
在具名表示法中,通过使用 => 将参数名与其对应的值表达式显式绑定:
SELECT concat_lower_or_upper(a => 'Hello', b => 'World'); concat_lower_or_upper ----------------------- hello world (1 row)
具名表示法的一大核心优势是实参的书写顺序完全自由:
SELECT concat_lower_or_upper(a => 'Hello', b => 'World', uppercase => true); concat_lower_or_upper ----------------------- HELLO WORLD (1 row) SELECT concat_lower_or_upper(a => 'Hello', uppercase => true, b => 'World'); concat_lower_or_upper ----------------------- HELLO WORLD (1 row)
为了向后兼容,系统同样支持基于 “:=” 的旧式赋值语法:
SELECT concat_lower_or_upper(a := 'Hello', uppercase := true, b := 'World'); concat_lower_or_upper ----------------------- HELLO WORLD (1 row)
混合表示法融合了位置表示法与具名表示法。其核心约束在于:具名参数绝不能出现在任何位置参数之前:
SELECT concat_lower_or_upper('Hello', 'World', uppercase => true);
concat_lower_or_upper
-----------------------
HELLO WORLD
(1 row)
在前述查询中,实参 a 与 b 按位置顺序传入,而 uppercase 按名称指定。面对包含大量可选配置项的复杂函数时,混合表示法能够显著精简书写并大幅降低传参错误的几率。
目前在直接调用聚合函数时暂不支持使用具名与混合调用表示法(但当聚合函数作为窗口函数调用时支持使用)。