如果 table 不存在,如何 SELECT 不出错
How to SELECT without error if table does not exist
我想从给定的 table 运行 SELECT
,如果 table 不存在,这应该不会失败。为简单起见,假设 table 仅包含一列和一行,而我在该标量之后。如果 table 不存在我想返回 0
.
我知道我可以做类似的事情:
query("select count(1) from information_schema.tables where table_name = 'versions'")
if result > 0
return query("select version from versions limit 1")
else
return 0
或者我可以使用存储过程/plpgsql 函数做同样的事情。
但是有没有办法在单个临时查询中执行相同的操作?
(我正在执行两个查询。我没有充分的理由更改它。我只是好奇 whether/how 是否可以这样做。)
我相信一个简短的 PLpg/SQL 函数就是您要找的。您可以检查 table 是否存在于 information_schema.tables
中,就像您一直在做的那样,并将此结果存储在变量中。之后,您可以在 IF
语句和 return 中评估结果集,无论您想要什么,例如
CREATE OR REPLACE FUNCTION f(p_table_name TEXT)
RETURNS INT
LANGUAGE plpgsql AS
$BODY$
DECLARE
res INT;
BEGIN
SELECT count(*)
into res
FROM information_schema.tables
WHERE table_name = p_table_name;
IF res>0 THEN RETURN res;
ELSE RETURN 0;
END IF;
END
$BODY$;
不存在table
SELECT * FROM f('versions');
f
---
0
(1 Zeile)
现有table
SELECT * FROM f('t');
f
---
1
(1 Zeile)
您希望使用纯 SQL 解决方案与服务器进行单次往返。
这些年来,有许多相关的请求。 原则上不可能。
- 您或者需要动态SQL - 这需要使用PL/pgSQL或其他PL的函数。
- 或您需要两次到服务器的往返行程。先查存在,再查询。
您还 不能 将它嵌套在一个普通的 SQL 函数中,它会在执行前计划主体中的每个语句,并在尝试解析不存在的语句时失败table 姓名。它甚至不会在函数创建时通过表面测试。参见:
针对您的简单案例的两个简单解决方案(在许多可能的方法中):
CREATE OR REPLACE FUNCTION f_select_version_if_exists1()
RETURNS int LANGUAGE plpgsql PARALLEL SAFE AS
$func$
BEGIN
IF EXISTS (
SELECT FROM pg_catalog.pg_tables
WHERE tablename = 'versions'
AND schemaname = 'public' -- see below!
) THEN
RETURN (SELECT version FROM versions LIMIT 1);
ELSE
RETURN 0;
END IF;
END
$func$;
或者:
CREATE OR REPLACE FUNCTION f_select_version_if_exists2(INOUT _version int = 0) AS
$func$
BEGIN
IF EXISTS (
SELECT FROM pg_catalog.pg_tables
WHERE tablename = 'versions'
AND schemaname = 'public' -- see below!
) THEN
SELECT INTO _version version
FROM versions LIMIT 1;
END IF;
END
$func$ LANGUAGE plpgsql PARALLEL SAFE;
我强烈建议同时确定架构名称。 Table 名称在 Postgres 中不是唯一的。参见:
- How to check if a table exists in a given schema
此外,我创建了函数 PARALLEL SAFE
(仅当它可能嵌套在 big 查询中时才重要)。这将是 错误的 而依赖 search_path
因为它通常包括临时对象的模式,这使得它 PARALLEL UNSAFE
第二个是创造性地使用 INOUT
参数。相关:
- Can I make a plpgsql function return an integer without using a variable?
我想从给定的 table 运行 SELECT
,如果 table 不存在,这应该不会失败。为简单起见,假设 table 仅包含一列和一行,而我在该标量之后。如果 table 不存在我想返回 0
.
我知道我可以做类似的事情:
query("select count(1) from information_schema.tables where table_name = 'versions'")
if result > 0
return query("select version from versions limit 1")
else
return 0
或者我可以使用存储过程/plpgsql 函数做同样的事情。
但是有没有办法在单个临时查询中执行相同的操作?
(我正在执行两个查询。我没有充分的理由更改它。我只是好奇 whether/how 是否可以这样做。)
我相信一个简短的 PLpg/SQL 函数就是您要找的。您可以检查 table 是否存在于 information_schema.tables
中,就像您一直在做的那样,并将此结果存储在变量中。之后,您可以在 IF
语句和 return 中评估结果集,无论您想要什么,例如
CREATE OR REPLACE FUNCTION f(p_table_name TEXT)
RETURNS INT
LANGUAGE plpgsql AS
$BODY$
DECLARE
res INT;
BEGIN
SELECT count(*)
into res
FROM information_schema.tables
WHERE table_name = p_table_name;
IF res>0 THEN RETURN res;
ELSE RETURN 0;
END IF;
END
$BODY$;
不存在table
SELECT * FROM f('versions');
f
---
0
(1 Zeile)
现有table
SELECT * FROM f('t');
f
---
1
(1 Zeile)
您希望使用纯 SQL 解决方案与服务器进行单次往返。 这些年来,有许多相关的请求。 原则上不可能。
- 您或者需要动态SQL - 这需要使用PL/pgSQL或其他PL的函数。
- 或您需要两次到服务器的往返行程。先查存在,再查询。
您还 不能 将它嵌套在一个普通的 SQL 函数中,它会在执行前计划主体中的每个语句,并在尝试解析不存在的语句时失败table 姓名。它甚至不会在函数创建时通过表面测试。参见:
针对您的简单案例的两个简单解决方案(在许多可能的方法中):
CREATE OR REPLACE FUNCTION f_select_version_if_exists1()
RETURNS int LANGUAGE plpgsql PARALLEL SAFE AS
$func$
BEGIN
IF EXISTS (
SELECT FROM pg_catalog.pg_tables
WHERE tablename = 'versions'
AND schemaname = 'public' -- see below!
) THEN
RETURN (SELECT version FROM versions LIMIT 1);
ELSE
RETURN 0;
END IF;
END
$func$;
或者:
CREATE OR REPLACE FUNCTION f_select_version_if_exists2(INOUT _version int = 0) AS
$func$
BEGIN
IF EXISTS (
SELECT FROM pg_catalog.pg_tables
WHERE tablename = 'versions'
AND schemaname = 'public' -- see below!
) THEN
SELECT INTO _version version
FROM versions LIMIT 1;
END IF;
END
$func$ LANGUAGE plpgsql PARALLEL SAFE;
我强烈建议同时确定架构名称。 Table 名称在 Postgres 中不是唯一的。参见:
- How to check if a table exists in a given schema
此外,我创建了函数 PARALLEL SAFE
(仅当它可能嵌套在 big 查询中时才重要)。这将是 错误的 而依赖 search_path
因为它通常包括临时对象的模式,这使得它 PARALLEL UNSAFE
第二个是创造性地使用 INOUT
参数。相关:
- Can I make a plpgsql function return an integer without using a variable?