在雪花中处理无穷大和NaN

时间:2020-09-21 16:17:56

标签: snowflake-cloud-data-platform

我正在将数据仓库前端从Hadoop后端转换为Snowflake后端,我需要将其每个SQL函数转换为等效的Snowflake。我遇到的一件事是处理产生Infinity / -Infinity或NaN(非数字)的公式。

在Hadoop中,这是使用IS_INF和IS_NAN检查公式的简单问题。在SQL Server(我们测试过的另一个后端)中,可以使用SET ARITHABORT OFF / SET ANSI_WARNINGS OFF来完成。 Hadoop方法向SQL添加了额外的逻辑检查,而SQL Server方法只是直接忽略了错误并返回NULL而不是抛出错误。我更喜欢后一种方法,因为它不会减慢查询速度,但是我对在Snowflake中实际可用的任何方法都持开放态度,因为到目前为止,我找不到任何方法。

我应该注意,有Snowflake函数可以帮助避免非常具体的错误,例如除以零(即DIV0函数或NULLIF),但这对我没有帮助,原因有两个。首先,这仅处理某些问题(除以零)。我需要可以处理任何生成Inf / NaN的公式的东西。其次,有问题的公式通常由最终用户在前端编写,这意味着我不知道公式的哪一部分是除数,哪一部分是除数。该公式可能非常复杂(包括CASE WHEN或其他函数或任何其他事物),因此解析除数(以便我可以使用NULLIF),或者解析除数和除数(以便我可以使用DIV0)是真的不是一个选择。

我注意到Snowflake的文档,其中说FLOAT数据类型可以处理诸如Infinity和NaN之类的特殊值,但我看不出有什么方法可以在公式中实际生成这些值而不会引发错误。

任何帮助将不胜感激。

1 个答案:

答案 0 :(得分:1)

(据我所知)没有无限NaN值的内置便捷函数。特别是没有达到您想要的程度。我不必在自己的工作中处理数字无限成为问题的情况,但是我们可以通过创建自己的函数来至少实现某些功能。在这种情况下,我们可以仅使用SQL-UDF就能摆脱困境,而Javascript具有更大的灵活性。
下面,我为此定义了4个函数(IS_INFIS_NAIF_NAIF_INF)。请注意,这些函数采用变量输入并返回变量输出。就是这样,我不必为所有不同的data types重载该函数。实际上,这仅对varchar和派生类型(日期,时间戳记)以及可能的地理空间数据有问题,这些数据必须转换为VARIANT。

CREATE FUNCTION IS_INF(x VARIANT)
RETURNS boolean
AS 
$$
    iff(try_cast(x::varchar as float) IN ('Inf', -'Inf'), TRUE, FALSE)
$$;
CREATE FUNCTION IS_NA(x VARIANT)
RETURNS boolean
AS 
$$
    iff(try_cast(x::varchar as float) = 'NaN', TRUE, FALSE)
$$;
CREATE FUNCTION IF_NA(x VARIANT, y VARIANT, z VARIANT)
RETURNS VARIANT 
AS 
$$
    iff(try_cast(x::varchar as float) = 'NaN', y, z)
$$;
CREATE FUNCTION IF_INF(x VARIANT, y VARIANT, z VARIANT)
RETURNS VARIANT 
AS 
$$
    iff(try_cast(x::varchar as float) IN ('Inf', -'Inf'), y, z)
$$;

请注意,这要求将它们存储在特定的架构中,因此,如果希望将其存储在另一架构或数据库中,则必须选择特定的架构。为此目的拥有数据库/架构通常会有所帮助。此外,雪花确实允许使用IS_NAN,但此后我无法使用此功能。

用法示例

select is_inf(3245); -- false
SELECT is_na('NaN'); -- true
SELECT IF_inf(3245, 'NaN'::float, 4); -- 4
SELECT if_na(3245, TRUE, FALSE); -- false