PostgreSQL 17: 在 PL/pgSQL 中允许 %TYPE 和 %ROWTYPE 带数组修饰符

John Doe 六月 12, 2025

你需要在存储过程中定义未知类型的数组吗?现在,PL/pgSQL 允许 %TYPE 和 %ROWTYPE 带数组修饰符了。

草原上奔驰的大象

特性提交日志

在 PL/pgSQL 中,允许 %TYPE 和 %ROWTYPE 后接数组修饰符。

这提供了一项实用功能,可用于声明一个变量,该变量为其他某个变量或某个表列类型的数组。

讨论:https://postgr.es/m/ec4523e1-9e7e-f3ef-f9ce-bafd680ad6f6@yeah.net

示例

在编写 PL/pgSQL 的函数/存储过程/匿名块时,可以使用变量。每个变量都有类型。例如:

user_hash text;
all_hashes text[];

这定义了一个名为 user_hash、数据类型为 text 的变量,以及另一个名为 all_hashes 的变量,它是文本数组(其中 [] 表示数组)。

除此之外,还可以使用伪类型 %TYPE 和 %ROWTYPE,如下所示:

user_hash users.password%TYPE;
user_row users%ROWTYPE;

这里我们再次声明了两个变量,但它们的类型是基于数据库中已有的内容评估的。具体来说,user_hash 将具有与 users 表中 password 列相同的类型,而 user_row 将被定义为与 users 表结构相同的记录类型。

问题在于,在之前的 PostgreSQL 版本中,我们无法轻松地将变量定义为 %TYPE 或 %ROWTYPE 的数组。现在可以这样做了:

DO $$
DECLARE
    v_all_db_names pg_database.datname%TYPE[];
    v_all_dbs pg_database%ROWTYPE[];
BEGIN
    select array_agg(datname) into v_all_db_names FROM pg_database;
    select array_agg(d) into v_all_dbs FROM pg_database d;
    raise notice 'All db names = %', v_all_db_names;
    raise notice 'All dbs = %', v_all_dbs;
END;
$$;

输出结果:

NOTICE:  All db names = {postgres,template1,template0,pgdba,redrock}
NOTICE:  All dbs = {
"(5,postgres,10,6,c,f,t,f,-1,728,1,1663,en_US.UTF-8,en_US.UTF-8,,,2.37,)",
"(1,template1,10,6,c,t,t,f,-1,728,1,1663,en_US.UTF-8,en_US.UTF-8,,,2.37,\"{=c/pgdba,pgdba=CTc/pgdba}\")",
"(4,template0,10,6,c,t,f,f,-1,728,1,1663,en_US.UTF-8,en_US.UTF-8,,,,\"{=c/pgdba,pgdba=CTc/pgdba}\")",
"(16462,pgdba,10,6,c,f,t,f,-1,728,1,1663,en_US.UTF-8,en_US.UTF-8,,,2.37,)",
"(16473,redrock,16384,6,c,f,t,f,-1,728,1,1663,en_US.UTF-8,en_US.UTF-8,,,2.37,)"}

非常不错的特性。这使得将记录集轻松且良好地存储在变量中成为可能,以便后续可以重复使用。

感谢社区的所有相关人员。

参考

提交日志:https://git.postgresql.org/pg/commitdiff/5e8674dc83926f52516f847f1a77e8d38e94e143