在PostgreSQL中,我想创建一个安全包装机制,如果发生异常则返回空结果。请考虑以下事项:
SELECT * FROM myschema.mytable;
我可以在客户端应用程序中进行安全包装:
try {
result = execute_query('SELECT value FROM myschema.mytable').fetchall();
}
catch(pg_exception) {
result = []
}
但是我可以直接在SQL中做这样的事情吗?我想让下面的代码工作,但似乎应该放入DO $$ ... $$
块,这里我迷路了。
BEGIN
SELECT * FROM myschema.mytable;
EXCEPTION WHEN others THEN
SELECT unnest(ARRAY[]::TEXT[])
END
答案 0 :(得分:12)
通常,plpgsql代码始终包含在BEGIN .. END
块中。这可以在DO
语句或函数的主体内部。块可以嵌套在内部 - 但它们不能存在于外部,不要将它与普通SQL混淆。
每个BEGIN
块可以选择包含用于处理异常的EXCEPTION
子句,但是需要捕获异常的函数要贵得多,因此最好先避免异常。< / p>
更多信息:
The manual on how to trap errors (handle exceptions) in PL/pgSQL
示例:Is SELECT or INSERT in a function prone to race conditions?
DO
语句无法返回任何内容。 Create a function将表和模式名称作为参数并返回您想要的任何内容:
CREATE OR REPLACE FUNCTION f_tbl_value(_tbl text, _schema text = 'public')
RETURNS TABLE (value text) AS
$func$
DECLARE
_t regclass := to_regclass(_schema || '.' || _tbl);
BEGIN
IF _t IS NULL THEN
value := ''; RETURN NEXT; -- return single empty string
ELSE
RETURN QUERY EXECUTE
'SELECT value FROM ' || _t; -- return set of values
END
$func$ LANGUAGE plpgsql;
致电:
SELECT * FROM f_tbl_value('my_table');
或者:
SELECT * FROM f_tbl_value('my_table', 'my_schema');
假设您想要一组具有单个text
列的行,或者如果该表不存在则需要空字符串。
如果给定的表存在,还假设存在列value
。你也可以测试一下,但是你并没有要求它。
这两个参数均为区分大小写 text
值。这与identifiers in SQL statements are handled的方式略有不同。如果你从不重复引用标识符,请传递小写名称,你没事。
在我的示例中,架构名称默认为'public'
。适应您的需求。您甚至可以完全忽略架构,默认为当前search_path
。
to_regclass()
是Postgres 9.4 的新功能。对于旧版本替代:
IF EXISTS (
SELECT 1
FROM information_schema.tables
WHERE table_schema = _schema
AND table_name = _tbl
);
这实际上是更准确,因为它可以准确测试您的需求。 更多选项和详细解释:
使用动态SQL时始终防御SQL注入!演员到regclass
就可以了。更多细节:
答案 1 :(得分:0)
如果您只选择一列,那么COALESCE()函数应该能够为您做到这一点
SELECT COALESCE( value, '{}'::text[] ) FROM myschema.mytable
如果您需要更多行,则可能需要创建具有类型的函数。