PostgreSQL如何将SELECT查询结果存为变量并用于FOR循环操作
PL/pgSQL 中存储查询结果集的变量定义与赋值方法
针对你需要把SELECT DISTINCT查询结果存为变量、后续遍历的场景,常用的变量定义和赋值方式分两类:
- 单字段多行结果(比如仅提取a表的DISTINCT id)
- 数组类型:变量格式为
ids a.id[],赋值时通过聚合函数拼接结果,写法为SELECT ARRAY_AGG(DISTINCT id) INTO ids FROM a;,适合结果集规模适中的场景 - 游标类型:变量格式为
ids refcursor,赋值时直接绑定查询语句,不会一次性把全量数据加载到内存,适合结果集较大的场景
- 数组类型:变量格式为
- 多字段结果
- TABLE类型复合变量:自定义表结构存储多列结果,赋值时直接把查询结果插入表变量即可
- 临时表:适合超大规模结果集的存储,使用完毕可自动或手动清理
现有代码的常见语法问题
你写的代码片段存在几处直接影响运行的语法错误:
SELECT DISTINCT (*)语法无效,需要明确指定要提取的字段名,比如只取id就写SELECT DISTINCT id FROM a- 循环内的INSERT语句缺少闭合括号,
SELECT FROM c缺少明确的取值范围,语法不完整 - 循环取出的单个id值不需要搭配
IN操作符,等值匹配c.id = 单个id值即可
可直接运行的实现代码
按你预期的「先存结果集变量、再遍历插入」写法
do $$ declare -- 定义和a表id类型匹配的数组变量,存储所有DISTINCT的id值 ids a.id[]; -- 循环迭代用的临时变量,和a.id类型保持一致 loop_id a.id%type; begin -- 将DISTINCT查询结果赋值给数组变量 SELECT ARRAY_AGG(DISTINCT id) INTO ids FROM a; -- 遍历数组内的每个id FOREACH loop_id IN ARRAY ids LOOP -- 匹配c表对应id的数据,插入b表 INSERT INTO b SELECT * FROM c WHERE c.id = loop_id; END LOOP; end $$;
更高效的无循环实现(推荐)
注意:能通过单条关联SQL完成的逻辑,尽量不要写逐行循环的PL/pgSQL逻辑,单SQL的执行效率远高于循环遍历,还能避免代码冗余:
do $$ begin -- 直接关联a表的去重结果和c表,一次性完成数据插入 INSERT INTO b SELECT DISTINCT c.* FROM c JOIN (SELECT DISTINCT id FROM a) a_dist ON c.id = a_dist.id; end $$;
内容的提问来源于stack exchange,提问作者YVS1997
相关产品推荐
相关产品推荐

