Microsoft SQL Server 有一个我认为非常明智的函数,如果强制转换不成功,try_cast()
它会返回 a null
,而不是引发错误。
这使得可以使用CASE
表达式或 acoalesce
来回退。例如:
SELECT coalesce(try_cast(data as int),0);
问题是,PostgreSQL 有类似的东西吗?
提出这个问题是为了填补我的知识空白,但也有一般原则,即有些人更喜欢对某些用户错误做出不那么戏剧性的反应。null
在 SQL 中返回 a比返回错误更容易。例如SELECT * FROM data WHERE try_cast(value) IS NOT NULL;
. 根据我的经验,如果有 B 计划,有时会更好地处理用户错误。
基本原理
很难将SQL Server 之
TRY_CAST
类的东西包装到通用 PostgreSQL 函数中。输入和输出可以是任何数据类型,但 SQL 是严格类型的,并且 Postgres 函数要求在创建时声明参数和返回类型。Postgres 有多态类型的概念,但函数声明最多接受一种多态类型。手册:
CAST ( expression AS type )
似乎是该规则的一个例外,采用任何类型并返回任何(其他)类型。但它cast()
只是看起来像一个函数,而它实际上是一个SQL 语法元素。手册:输入和输出类型的每种组合都有一个单独的函数。(您可以使用...创建自己的
CREATE CAST
)功能
我的妥协是
text
用作输入,因为任何类型都可以转换为text
. 额外的演员text
意味着额外的成本(虽然不多)。多态性也增加了一些开销。但成本适中的部分是我们需要的动态 SQL、涉及的字符串连接以及最重要的异常处理。也就是说,这个小函数可以用于任何类型的组合,包括数组类型。(但是像 in 这样的类型修饰符
varchar(20)
丢失了):该
INOUT
参数_out
有两个用途:你不会像在你的例子中那样称呼它:
.. where
COALESCE
还从源中消除了真正的 NULL 值(!!),可能不是预期的。但简单地说:..返回输入或无效输入
NULL
。NULL
0
短语法适用 while
data
是字符类型(如text
orvarchar
),因为0
是隐式类型为 的数字文字integer
。在其他情况下,您可能必须更明确:示例调用
无类型的字符串文字开箱即用:
具有已注册隐式转换的类型值
text
也可以开箱即用:已注册隐式强制转换为的数据类型的综合列表
text
:所有其他输入类型都需要显式转换为
text
:我们可以轻松地使函数体适用于任何类型,但函数类型解析失败。有关的:
如果从一种特定类型转换为另一种特定类型就足够了,您可以使用 PL/pgSQL 函数执行此操作:
然后
退货
如果这仅适用于数字,另一种方法是使用正则表达式来检查输入字符串是否为有效数字。当您期望许多不正确的值时,这可能比捕获异常更快。
这是一个通用的 try-cast,可能非常慢。
这不会接受类似的类型
varchar(20)
(尽管我们可以添加另一个参数来接受“typemod” like20
.此函数返回文本,因为 postgreqsl 函数必须具有固定的返回类型。因此您可能需要在函数之外进行显式强制转换,以将结果强制转换为您想要的类型。
稍有不同的通用版本 - 这将返回 true 或 false,具体取决于是否可以转换该值。也适用于用户定义的域。这适用于 PostgreSQL 12。
我已经接受了一个答案,但我想我可能会为后代添加这个。这是我在工作中使用的版本:
这基本上来自a_horse_with_no_name 上面的答案,但只是更巩固了一点。
MSSQL
TRY_CAST
在数据类型方面更为通用,就像CAST
函数本身一样。此版本需要针对不同数据类型使用不同的函数,例如cast_date
. 您可以扩展它以自己检查数据类型,但这可能太过分了。使用 PostgreSQL,当强制执行失败时,它会在内部使用
ereport
. 这在强制中是无法恢复的。样本数据
假设错误率为 1/5
将不良数据列入黑名单。
这个问题的正常解决方案是在创建类型时自由地接受。这几乎就是现在的工作方式。如果您需要防止某种虚假输入,而不是在失败的情况下捕获,只需在失败之前将其设置为 null。
如果您愿意,也可以将其放入
IMMUTABLE
SQL 语句中。就验证而言,您还可以使用正则表达式和您想要的任何其他内容。
试着抓
这种方法很慢。
如果你需要它,那么无论如何你都需要它,但它不会是我抢的第一个工具。