如何用单条临时查询实现表存在取标量、不存在返回0且不报错?
实现单条查询获取表值(表不存在时返回0)
当然可以实现,但有个关键前提得先说明:PostgreSQL在查询解析阶段会验证所有引用的表是否存在,哪怕这些表出现在永远不会执行的条件分支里。所以直接写包含versions表的CASE或UNION语句,只要表不存在就会报错,没法通过条件跳过。
不过我们可以用临时PL/pgSQL函数来实现单条会话级的ad-hoc逻辑(函数会在会话结束后自动消失,不会污染数据库),或者用DO块配合临时表来返回结果。
方法1:临时函数(推荐)
这个方法最简洁,而且函数仅在当前会话有效:
CREATE OR REPLACE FUNCTION get_version() RETURNS integer AS $$ BEGIN -- 尝试查询表中的值 RETURN (SELECT version FROM versions LIMIT 1); EXCEPTION -- 捕获表不存在的错误,返回0 WHEN undefined_table THEN RETURN 0; END; $$ LANGUAGE plpgsql VOLATILE; -- 调用函数获取结果 SELECT get_version();
你可以把这两行语句作为一个整体执行,本质上是创建一个临时函数(会话结束后自动删除)并立即调用,完全符合ad-hoc查询的需求。
方法2:DO块+临时表
如果你不想创建函数,可以用DO块处理异常,把结果存入临时表再查询:
DO $$ BEGIN -- 尝试从表中获取值存入临时表 CREATE TEMP TABLE temp_version_result AS SELECT version AS result FROM versions LIMIT 1; EXCEPTION WHEN undefined_table THEN -- 表不存在时存入0 CREATE TEMP TABLE temp_version_result AS SELECT 0 AS result; END $$; -- 查询临时表得到结果 SELECT result FROM temp_version_result;
同样,这两行可以一起执行,临时表也会在会话结束后自动清理。
为什么直接SELECT不行?
如开头所说,PostgreSQL的查询解析是提前完成的:只要你的查询语句里出现了versions这个表名,不管它在CASE的THEN分支还是UNION的某个部分,数据库都会先检查这个表是否存在,不存在就直接抛出错误,不会等到执行阶段再判断条件。这也是为什么你最初的两次查询是更直接的安全方式——分开执行的话,第二次查询只有在表存在时才会被解析执行。
内容的提问来源于stack exchange,提问作者viraptor
相关产品推荐
相关产品推荐

