正确地将Postgres最少()行为迁移到BigQuery

时间:2017-05-05 03:53:36

标签: sql postgresql google-bigquery google-cloud-platform

我试图将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行为,我们非常感谢!

4 个答案:

答案 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