正确将Postgres minimum()行为迁移到BigQuery

Gra*_*ace 2 sql postgresql google-bigquery google-cloud-platform

我正在尝试将postgres脚本迁移到bigquery,最终目的是两个脚本都返回完全相同的表(模式和值)。

尝试在我的bigquery select中复制postgres中的minimum()行为时遇到问题。

在postgres中,如果minimum()调用的任何参数为null,则将跳过它们并返回最小非null值。但是,在bigquery中,如果minimum()调用的任何参数为null,则该函数自动返回null。

我正在寻找一种优雅的解决方案来复制bigquery中的postgres minimum()行为。我当前的笨拙解决方案如下:

Postgres(返回-1):

SELECT LEAST(1, 0, -1, null)
Run Code Online (Sandbox Code Playgroud)

BigQuery(返回null):

SELECT LEAST(1, 0, -1, null)
Run Code Online (Sandbox Code Playgroud)

Postgres(返回-1):

SELECT LEAST(COALESCE(1, 0, -1, null),
             COALESCE(0, 1, -1, null),
             COALESCE(-1, 0, 1, null),
             COALESCE(null, 0, -1, 1))
Run Code Online (Sandbox Code Playgroud)

BigQuery(返回-1):

SELECT LEAST(COALESCE(1, 0, -1, null),
             COALESCE(0, 1, -1, null),
             COALESCE(-1, 0, 1, null),
             COALESCE(null, 0, -1, 1))
Run Code Online (Sandbox Code Playgroud)

这是可行的,但不是理想的解决方案。

在我需要迁移的原始postgres脚本中,存在嵌套的逻辑,例如least(w, x, least(y, z)),随着值/复杂度的增长,修复变得指数级地不可读。当您尝试将其作为一个巨大的CASE块时,也会遇到相同的问题。

如果有人能找到我所缺少的明显修补程序,或者以更优雅的方式来反映bigquery中的postgres行为,我们将不胜感激!

小智 8

没有函数:

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
Run Code Online (Sandbox Code Playgroud)


Mos*_*sky 6

Oracle 和 Vertica 的行为与 BigQuery 相同,遵循 SQL 函数的一般规则 - 如果参数之一为 NULL - 结果为 NULL。PostgreSQL对该规则有一个例外,在文档中明确指出:

仅当所有表达式的计算结果均为 NULL 时,结果才会为 NULL。

请注意,GREATEST 和 LEAST 不在 SQL 标准中,而是常见的扩展。其他一些数据库使它们在任何参数为 NULL 时返回 NULL,而不是仅当所有参数均为 NULL 时才返回 NULL。

我会在 BigQuery 问题跟踪器中打开功能请求,将IGNORE NULLS参数添加到 LEAST 和 GREATEST 以获得 PostgreSQL 兼容的行为。尽管通常IGNORE NULLS仅适用于聚合函数,但 LEAST 和 GREATEST 与聚合函数有点相似。


Mik*_*ant 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  
Run Code Online (Sandbox Code Playgroud)

输出是

least_standard  least_less_than_ideal   least_workaround    least_with_nested    
null            -1                      -1                  -2   
Run Code Online (Sandbox Code Playgroud)

前两个来自您的问题-第三个是“独立”和嵌套的解决方法

希望您可以将这种方法应用于您的特定情况