在 BigQuery 中包含带有 ANY_VALUE 的空值

d3w*_*abe 6 aggregate-functions google-bigquery

我有一个“供应商”表,看起来像这样......

**company itemKey itemPriceA itemPriceB**
companyA, 203913, 20, 10
companyA, 203914, 20, 20
companyA, 203915, 25, 5
companyA, 203916, 10, 10
Run Code Online (Sandbox Code Playgroud)

每个公司可能有数百万行,我想查询它以返回每个公司的 itemPriceA 和 itemPriceB 之间的代表性增量。我不在乎我带回哪个增量,只要它不是零/空(如第2行或第4行),所以我使用像这样的ANY_VALUE...

SELECT company
, ANY_VALUE(CASE WHEN (itemPriceA-itemPriceB)=0 THEN null ELSE (itemPriceA-itemPriceB) END)
FROM vendors
GROUP BY 1
Run Code Online (Sandbox Code Playgroud)

它似乎有效,但我注意到谷歌文档中有两句话似乎矛盾......

"当组中所有行的表达式为 NULL 时,返回 NULL。ANY_VALUE 的行为就像指定了 RESPECT NULLS;将考虑并选择表达式为 NULL 的行。 "

如果 ANY_VALUE 返回 null“当组中所有行的表达式为 NULL 时”,它不应该为 companyA 返回 null,正确的(因为 4 行中只有 2 行为 null)?但第二句话听起来确实会包含空行。

Ps,您可能想知道为什么我不简单地添加一个 WHERE 子句“WHERE itemPriceA-itemPriceB>0”,但如果一家公司只有匹配的价格,我仍然希望该公司在我的结果中返回。

149*_*203 7

澄清

恐怕所接受的答案必须提供与文档相矛盾的更有力的证据。

@Raul Saucedo 建议以下 BigQuery 文档引用 WHERE 子句:

考虑并选择表达式为 NULL 的行

不是这种情况。ANY_VALUE 文档中的任何地方都没有提到 WHERE 子句。(页面上没有任何地方上没有任何地方。尝试一下ctrl+f。)正如我将解释的那样,文档很清楚。

@d3wannabe 对此的疑问是正确的:

它似乎有效,但我注意到谷歌文档中有两句话似乎矛盾......

“当组中所有行的表达式为 NULL 时,返回 NULL。ANY_VALUE 的行为就像指定了 RESPECT NULLS;表达式为 NULL 的行将被考虑并可能被选择。”

但这些文档并不矛盾。2句话并存。

  1. “当组中所有行的表达式均为 NULL 时,返回 NULL。” 因此,如果列中的所有行均为 NULL,则将返回 NULL。
  2. “ANY_VALUE 的行为就像指定了 RESPECT NULLS;表达式为 NULL 的行将被考虑并可能被选择。”因此,如果该列中有混合有 NULL 和实际数据的行,它将从该列中选择任何内容,包括 null。

如何在 BigQuery 中创建不含 null 的 ANY_VALUE

我们可以使用ARRAY_AGG将一组值转换为列表。该聚合函数可以选择 INGORE NULLS。然后,我们在忽略空值后从列表中选择 1 项。

如果我们有一个包含 2 列的表:idmixed_data,其中mixed_data一些行包含空值:

SELECT
    id,
    ARRAY_AGG( -- turn the mixed_data values into a list
        mixed_data -- we'll create an array of values from our mixed_data column
        IGNORE NULLS -- there we go!
        LIMIT 1 -- only fill the array with 1 thing
    )[SAFE_OFFSET(0)] -- grab the first item in the array
    AS any_mixed_data_without_nulls
FROM your_table
GROUP BY id
Run Code Online (Sandbox Code Playgroud)

在这里查看类似的答案:

更新,2022年8月12日

有证据表明文档可能与函数的实际行为不一致。查看Samuel 的最新回答来探索他的方法论。

但是,我们无法知道文档是否不正确且 ANY_VALUE 的行为符合预期,或者 ANY_VALUE 是否存在错误且文档表达了预期的行为。我们不知道 Google 在解决此问题时是否会更正文档或功能。

因此,我将继续使用 ARRAY_AGG 创建一个忽略空值的安全 ANY_VALUE,直到我们看到 Google 的修复。

请在 Google 的问题跟踪器中对该问题进行投票,以解决此问题。


小智 3

这是关于 \xe2\x80\x9cany_value 如何与 null 值\xe2\x80\x9d 一起使用的说明。

\n

对于any_value,如果存在不同于null 的值,则始终返回第一个值。

\n
SELECT ANY_VALUE(fruit) as any_value\nFROM UNNEST([null, "banana",null,null]) as fruit;\n
Run Code Online (Sandbox Code Playgroud)\n

如果所有行都有 null 值,则返回 null。指的是这句话

\n
\n

\xe2\x80\x9c当组中所有行的表达式为 NULL 时返回 NULL\xe2\x80\x9d

\n
\n
SELECT ANY_VALUE(fruit) as any_value\nFROM UNNEST([null, null, null]) as fruit\n \n
Run Code Online (Sandbox Code Playgroud)\n

如果一个值为 null 并且您在 where 子句中指定,则返回 null。参考了这些句子

\n
\n

\xe2\x80\x9cANY_VALUE 的行为就像指定了 RESPECT NULLS 一样;考虑并选择表达式为 NULL 的行。\xe2\x80\x9d

\n
\n
SELECT ANY_VALUE(fruit) as any_value\nFROM UNNEST(["apple", "banana", null]) as fruit\nwhere fruit is null\n
Run Code Online (Sandbox Code Playgroud)\n

始终取决于您使用的过滤器以及any_value 内的字段。

\n

你可以看到这个例子,返回两行不为0的行。

\n
SELECT ANY_VALUE(e).company, (itemPriceA-itemPriceB) as value\nFROM `vendor` e\nwhere (itemPriceA-itemPriceB)!=0\ngroup by e.company\n
Run Code Online (Sandbox Code Playgroud)\n