从SQL Server迁移至PostgreSQL:除临时表外的局部变量实现方案问询
替代PostgreSQL临时表的局部变量方案
针对你从SQL Server迁移到PostgreSQL时遇到的局部变量替代问题,除了临时表,PostgreSQL还有几种更贴合你场景的方案,我按简洁度和适用场景整理如下:
1. 公共表表达式(CTE,WITH子句)
这是最接近你原有SQL逻辑的写法,不需要创建任何临时对象,直接复用查询结果,非常简洁。PostgreSQL会自动优化多次引用的CTE,确保users表只被查询一次:
-- 定义可复用的用户ID查询 WITH _usr AS ( SELECT id FROM users WHERE name = 'root' ) -- 依次查询三个表 SELECT * FROM info1 WHERE usr = (SELECT id FROM _usr); WITH _usr AS ( SELECT id FROM users WHERE name = 'root' ) SELECT * FROM info2 WHERE usr = (SELECT id FROM _usr); WITH _usr AS ( SELECT id FROM users WHERE name = 'root' ) SELECT * FROM info3 WHERE usr = (SELECT id FROM _usr);
如果希望在一个语句中返回所有结果(带来源标记),可以用UNION ALL:
WITH _usr AS ( SELECT id FROM users WHERE name = 'root' ) SELECT 'info1' AS data_source, * FROM info1 WHERE usr = (SELECT id FROM _usr) UNION ALL SELECT 'info2' AS data_source, * FROM info2 WHERE usr = (SELECT id FROM _usr) UNION ALL SELECT 'info3' AS data_source, * FROM info3 WHERE usr = (SELECT id FROM _usr);
2. 临时视图
比临时表更轻量,本质是一个临时的查询定义,不会实际存储数据,会话结束后自动消失:
-- 创建临时视图,会话内有效 CREATE TEMP VIEW _usr AS SELECT id FROM users WHERE name = 'root'; -- 复用视图查询三个表 SELECT * FROM info1 WHERE usr = (SELECT id FROM _usr); SELECT * FROM info2 WHERE usr = (SELECT id FROM _usr); SELECT * FROM info3 WHERE usr = (SELECT id FROM _usr); -- 手动清理(可选,会话结束会自动删除) -- DROP VIEW _usr;
3. psql客户端变量(交互式场景)
如果你用PostgreSQL官方的psql客户端操作,可以直接设置会话级变量,适合快速复用:
-- 执行SQL查询并将结果赋值给变量(反引号是shell命令替换) \set usr_id `SELECT id FROM users WHERE name = 'root'` -- 引用变量查询表 SELECT * FROM info1 WHERE usr = :usr_id; SELECT * FROM info2 WHERE usr = :usr_id; SELECT * FROM info3 WHERE usr = :usr_id;
4. 自定义函数(复用场景)
如果这个查询逻辑需要多次调用,可以封装成函数,虽然比前几种复杂,但适合长期复用:
CREATE OR REPLACE FUNCTION get_user_info(p_username varchar) RETURNS SETOF record AS $$ DECLARE _usr int; BEGIN -- 获取用户ID SELECT id INTO _usr FROM users WHERE name = p_username; -- 返回三个表的结果 RETURN QUERY SELECT * FROM info1 WHERE usr = _usr; RETURN QUERY SELECT * FROM info2 WHERE usr = _usr; RETURN QUERY SELECT * FROM info3 WHERE usr = _usr; END; $$ LANGUAGE plpgsql; -- 调用时需要指定结果集结构 SELECT * FROM get_user_info('root') AS info1(usr int, i1a text, i1b text); SELECT * FROM get_user_info('root') AS info2(usr int, i2a text, i2b text, i2c text); SELECT * FROM get_user_info('root') AS info3(usr int, i3a text, i2b decimal(10), i2c decimal(10), i2d decimal(10));
总结
你提到的匿名代码块确实在简单查询场景下不够简洁,上面的几种方案里,CTE和临时视图是最适合你当前需求的——既避免了临时表的存储开销,又能像SQL Server的局部变量一样复用查询结果。PostgreSQL没有像SQL Server那样的DECLARE @var直接局部变量(除了PL/pgSQL块内),但这些替代方案完全可以满足你的需求。
内容的提问来源于stack exchange,提问作者Raider




