我试图将postgres脚本迁移到bigquery,两个脚本的最终目标都返回完全相同的表(架构和值)。
我尝试在我的bigquery选择中复制postgres中的least()行为时遇到了问题。
在postgres中,如果least()调用的任何参数为null,则跳过它们并返回最小的非null值。但是,在bigquery中,如果least()调用的任何参数为null,则该函数自动返回null。
我正在寻找一个优雅的解决方案来复制bigquery中的postgres least()行为。我目前笨重的解决方案如下:
Postgres(返回-1
):
SELECT LEAST(1, 0, -1, null)
BigQuery(返回null
):
SELECT LEAST(1, 0, -1, null)
Postgres(返回-1
):
SELECT LEAST(COALESCE(1, 0, -1, null),
COALESCE(0, 1, -1, null),
COALESCE(-1, 0, 1, null),
COALESCE(null, 0, -1, 1))
BigQuery(返回-1
):
SELECT LEAST(COALESCE(1, 0, -1, null),
COALESCE(0, 1, -1, null),
COALESCE(-1, 0, 1, null),
COALESCE(null, 0, -1, 1))
这可行,但不是一个理想的解决方案。
在我需要迁移的原始postgres脚本中,存在像least(w, x, least(y, z))
这样的嵌套逻辑,因此随着值/复杂度的增加,修复得到指数级更难以理解。当您尝试将此作为大量CASE
块执行时,同样的问题也适用。
如果有人有一个明显的解决方案,我错过了或者更优雅的方式来反映bigquery中的postgres行为,我们非常感谢!
答案 0 :(得分:5)
BigQuery Standard SQL有一个简单的解决方法
你只需创建自己的功能(让我们说myLeast)
它适用于“独立”以及嵌套场景
#standardSQL
CREATE TEMP FUNCTION myLeast(x ARRAY<INT64>) AS
((SELECT MIN(y) FROM UNNEST(x) AS y));
SELECT
LEAST(1, 0, -1, NULL) AS least_standard,
LEAST(COALESCE(1, 0, -1, NULL),
COALESCE(0, 1, -1, NULL),
COALESCE(-1, 0, 1, NULL),
COALESCE(NULL, 0, -1, 1)) AS least_less_than_ideal,
myLeast([1, 0, -1, NULL]) AS least_workaround,
myLeast([1, 0, -1, NULL, myLeast([2, 0, -2, NULL])]) AS least_with_nested
输出
least_standard least_less_than_ideal least_workaround least_with_nested
null -1 -1 -2
前两个来自您的问题 - 第三个和第四个是“独立”和嵌套的解决方法
希望您可以将此方法应用于您的具体案例
答案 1 :(得分:2)
Oracle和Vertica的行为与BigQuery相同,遵循SQL函数的一般规则 - 如果其中一个参数为NULL - 结果为NULL。 PostgreSQL对该规则做了一个例外,在文档中明确说明:
仅当所有表达式求值为NULL时,结果才为NULL。
请注意,GREATEST和LEAST不在SQL标准中,但是是 共同延伸。一些其他数据库使它们返回NULL(如果有) 参数为NULL,而不是仅当全部为NULL时。
我会在BigQuery问题跟踪器中打开功能请求,将IGNORE NULLS
参数添加到LEAST和GREATEST以获得PostgreSQL兼容行为。尽管通常IGNORE NULLS
仅适用于聚合函数,但LEAST和GREATEST类似于聚合函数。
答案 2 :(得分:2)
没有功能:
select
(select min(col) from unnest([a,b,c,d,e]) col) least,
(select max(col) from unnest([a,b,c,d,e]) col) greatest,
*
from
(
select 1 a, 2 b, 3 c, null d, 5 e
union all
select null a, null b, null c, null d, null e
) tbl
答案 3 :(得分:0)
也许这样的事情可行?
WITH tbl AS(
SELECT 1 AS a, 2 AS b
UNION ALL SELECT NULL, 2
UNION ALL SELECT 1, NULL
UNION ALL SELECT NULL, NULL
)
SELECT
tbl.*
, COALESCE( LEAST(a, b), a , b)
FROM tbl