Man*_*ngo 13 postgresql datatypes error-handling cast
Microsoft SQL Server 有一个我认为非常明智的函数,如果转换不成功,try_cast()
它返回一个null
,而不是引发错误。
这使得可以使用CASE
表达式或 acoalesce
来回退。例如:
SELECT coalesce(try_cast(data as int),0);
Run Code Online (Sandbox Code Playgroud)
问题是,PostgreSQL 有没有类似的东西?
提出这个问题是为了填补我知识中的一些空白,但也有一个一般原则,即有些人更喜欢对某些用户错误做出不那么剧烈的反应。null
在 SQL 中返回 a比错误更容易。例如SELECT * FROM data WHERE try_cast(value) IS NOT NULL;
。根据我的经验,如果有 B 计划,有时可以更好地处理用户错误。
a_h*_*ame 13
如果从一种特定类型转换为另一种特定类型就足够了,您可以使用 PL/pgSQL 函数执行此操作:
create function try_cast_int(p_in text, p_default int default null)
returns int
as
$$
begin
begin
return $1::int;
exception
when others then
return p_default;
end;
end;
$$
language plpgsql;
Run Code Online (Sandbox Code Playgroud)
然后
select try_cast_int('42'), try_cast_int('foo', -1), try_cast_int('bar')
Run Code Online (Sandbox Code Playgroud)
退货
try_cast_int | try_cast_int | try_cast_int
-------------+--------------+-------------
42 | -1 |
Run Code Online (Sandbox Code Playgroud)
如果这仅适用于数字,另一种方法是使用正则表达式来检查输入字符串是否为有效数字。当您期望许多不正确的值时,这可能比捕获异常更快。
Erw*_*ter 12
很难将SQL Server 之TRY_CAST
类的东西包装到通用的 PostgreSQL 函数中。输入和输出可以是任何数据类型,但 SQL 是严格类型化的,并且 Postgres 函数要求在创建时声明参数和返回类型。
Postgres 有多态类型的概念,但函数声明最多接受一种多态类型。手册:
多态参数和结果相互关联,并在解析调用多态函数的查询时解析为特定的数据类型。声明为的每个位置(参数或返回值)
anyelement
都允许具有任何特定的实际数据类型,但在任何给定调用中,它们都必须是相同的实际类型。
CAST ( expression AS type )
似乎是这条规则的一个例外,采用任何类型并返回任何(其他)类型。但它cast()
只是看起来像一个函数,而它实际上是一个SQL 语法元素。手册:
[...] 当使用两种标准强制转换语法之一进行运行时转换时,它将在内部调用已注册的函数来执行转换。
输入和输出类型的每种组合都有一个单独的函数。(您可以使用CREATE CAST
...创建自己的)
我的妥协是text
用作输入,因为任何类型都可以转换为text
. 额外的演员text
意味着额外的成本(虽然不多)。多态性还增加了一些开销。但是中等成本的部分是我们需要的动态 SQL、涉及的字符串连接以及最重要的异常处理。
也就是说,这个小函数可用于任何类型的组合,包括数组类型。(但是像 in 这样的类型修饰符varchar(20)
丢失了):
CREATE OR REPLACE FUNCTION try_cast(_in text, INOUT _out ANYELEMENT) AS
$func$
BEGIN
EXECUTE format('SELECT %L::%s', $1, pg_typeof(_out))
INTO _out;
EXCEPTION WHEN others THEN
-- do nothing: _out already carries default
END
$func$ LANGUAGE plpgsql;
Run Code Online (Sandbox Code Playgroud)
该INOUT
参数有_out
两个用途:
你不会像在你的例子中那样称呼它:
SELECT coalesce(try_cast(data as int),0);
Run Code Online (Sandbox Code Playgroud)
.. whereCOALESCE
也从源 (!!) 中消除了真正的 NULL 值,可能不是预期的。但简单地说:
SELECT try_cast(data, 0);
Run Code Online (Sandbox Code Playgroud)
..NULL
在NULL
输入或0
无效输入时返回。
简短的语法在data
是字符类型(如text
或varchar
)时有效,因为0
是隐式类型为 的数字文字integer
。在其他情况下,您可能需要更加明确:
无类型字符串文字开箱即用:
SELECT try_cast('foo', NULL::varchar);
SELECT try_cast('2018-01-41', NULL::date); -- returns NULL
SELECT try_cast('2018-01-41', CURRENT_DATE); -- returns current date
Run Code Online (Sandbox Code Playgroud)
类型值是已注册的隐式转换到text
工作开箱即用,太:
SELECT try_cast(name 'foobar', 'foo'::varchar);
SELECT try_cast(my_varchar_column, NULL::numeric);
Run Code Online (Sandbox Code Playgroud)
具有注册隐式强制转换为的数据类型的综合列表text
:
SELECT castsource::regtype
FROM pg_cast
WHERE casttarget = 'text'::regtype
AND castcontext = 'i';
Run Code Online (Sandbox Code Playgroud)
所有其他输入类型都需要显式转换为text
:
SELECT try_cast((inet '192.168.100.128/20')::text, NULL::cidr);
SELECT try_cast(my_text_array_column::text, NULL::int[]));
Run Code Online (Sandbox Code Playgroud)
我们可以轻松地使函数体适用于任何类型,但函数类型解析失败。有关的: