BigQuery 中按键(或对称聚合)函数求和不同

Posted

技术标签:

【中文标题】BigQuery 中按键(或对称聚合)函数求和不同【英文标题】:Sum Distinct by key (or Symmetric Aggregates) function in BigQuery 【发布时间】:2019-11-20 17:19:01 【问题描述】:

我正在尝试通过对它们的键进行重复数据删除来对扇形/重复值求和。 Looker 将此称为对称聚合。我想使用持久的 UDF 而不是依赖子查询。 Looker 有一个非常优雅的解决方案,似乎可以将其烘焙到 UDF 中。

我试过了:

CREATE OR REPLACE FUNCTION `fn.sumdistinct`(unique_key ANY TYPE, val_to_sum ANY TYPE) AS (
 COALESCE(ROUND(COALESCE(CAST((SUM(DISTINCT (CAST(ROUND(COALESCE(safe_cast(val_to_sum as float64) ,0)*(1/1000*1.0), 9) AS NUMERIC) + (cast(cast(concat('0x', substr(to_hex(md5(CAST(unique_key  AS STRING))), 1, 15)) as int64) as numeric) * 4294967296 + cast(cast(concat('0x', substr(to_hex(md5(CAST(unique_key  AS STRING))), 16, 8)) as int64) as numeric)) * 0.000000001 )) - SUM(DISTINCT (cast(cast(concat('0x', substr(to_hex(md5(CAST(unique_key  AS STRING))), 1, 15)) as int64) as numeric) * 4294967296 + cast(cast(concat('0x', substr(to_hex(md5(CAST(unique_key  AS STRING))), 16, 8)) as int64) as numeric)) * 0.000000001) )  / (1/1000*1.0) AS FLOAT64), 0), 6), 0)
);

但我明白了:

Invalid function fn.sumdistinct. Aggregate function SUM not allowed in templated SQL function call

我在找一个可以转这个的函数:

id   val
1    100
2    200
2    200
3    300
3    300
3    300

进入:

unique_ids  total_value
3           600

【问题讨论】:

通常,UDF 以每行/记录为基础工作。所以select X, Y, udf_add(X,Y) as Z 在每行的基础上工作。它不会将表中的所有 XY 值加起来并聚合。您可以将您的值放入一个数组中,将该数组传递给一个 UDF,然后在 UDF 中对该数组尝试您的逻辑。找到解决您问题的不同查询模式(可能是 CTE)可能会更容易。 您为什么实际寻找在 UDF 中实现此功能的任何上下文,而您提供的示例如此自然地适合简单的 SQL 语句?了解您的确切用例将有助于我们为您提供帮助 【参考方案1】:

以下是 BigQuery 标准 SQL

#standardSQL
CREATE TEMP FUNCTION SumDistinct(arr ANY TYPE) AS ((
  SELECT AS STRUCT 
    COUNT(DISTINCT id) unique_ids, 
    SUM(val) total_value
  FROM (
    SELECT ANY_VALUE(t).*
    FROM UNNEST(arr) t
    GROUP BY FORMAT('%t', t)
  )
));
SELECT SumDistinct(ARRAY_AGG(STRUCT(id, val))).*
FROM `project.dataset.data`   

如果适用于您问题的样本数据 - 结果是

Row unique_ids  total_value  
1   3           600 

【讨论】:

【参考方案2】:

根据您希望如何将不同的 val 解析为相同的 id,您可以在下面的 sql 中调整聚合函数 (max(val)):

with data as 
(select 1 as id, 100 as val union all
select 1, 100 union all
select 1, 100 union all
select 2, 200 union all
select 2, 200 union all
select 3, 300 union all
select 3, 300
)
SELECT count(1) as unique_ids, sum(val) as total_value
FROM (
SELECT id, max(val) val
FROM data
GROUP BY id
)

【讨论】:

我通常会做这样的事情,但我正在寻找可以在 UDF 中使用的解决方案【参考方案3】:

您绝对可以在没有外部GROUP BY 的情况下执行此操作:

CREATE OR REPLACE FUNCTION `dataset.sumdistinct` (values array<struct<id int64, val int64>>) as (
  (
    select 
      struct(
       count(distinct x.id) as col1, 
       sum(distinct x.val) as col2
      ) from unnest(values) as x
  )
);

select sumdistinct(array_agg(struct(id as id, val as val))) from `dataset.table`

【讨论】:

【参考方案4】:

基于 cmets,您似乎希望 UDF 能够在内部调用聚合函数。也许您正在寻找用户定义的聚合函数,BigQuery 不支持该函数,但可以通过以下形式完成:

输出不是您所期望的,因为 UDF 无法像您的示例那样输出 2 列,希望您知道您需要对字段进行 array_agg() 并且您的 UDF 在内部执行 UNNEST() 并且能够使用系统聚合函数,如 SUM():

CREATE TEMP FUNCTION sumdistinct (unique_key INT64, val_array ARRAY<INT64>) AS (
 (SELECT COALESCE(ROUND(COALESCE(CAST((SUM(DISTINCT (CAST(ROUND(COALESCE(safe_cast(val_to_sum as float64) ,0)*(1/1000*1.0), 9) AS NUMERIC) + (cast(cast(concat('0x', substr(to_hex(md5(CAST(unique_key  AS STRING))), 1, 15)) as int64) as numeric) * 4294967296 + cast(cast(concat('0x', substr(to_hex(md5(CAST(unique_key  AS STRING))), 16, 8)) as int64) as numeric)) * 0.000000001 )) - SUM(DISTINCT (cast(cast(concat('0x', substr(to_hex(md5(CAST(unique_key  AS STRING))), 1, 15)) as int64) as numeric) * 4294967296 + cast(cast(concat('0x', substr(to_hex(md5(CAST(unique_key  AS STRING))), 16, 8)) as int64) as numeric)) * 0.000000001) )  / (1/1000*1.0) AS FLOAT64), 0), 6), 0)
 FROM unnest(val_array) val_to_sum)
);
with data as 
(select 1 as id, 100 as val union all
select 1, 100 union all
select 1, 100 union all
select 2, 200 union all
select 2, 200 union all
select 3, 300 union all
select 3, 300
)
SELECT sumdistinct(id, array_agg(val))
FROM data
GROUP BY id

【讨论】:

以上是关于BigQuery 中按键(或对称聚合)函数求和不同的主要内容,如果未能解决你的问题,请参考以下文章

是否有任何功能(将元组更改为数组)或(按键求和数组)?

Pyspark 将列列表转换为聚合函数

15group by子句与聚合函数

Rcpp:使用相等范围按键对多图值求和

BigQuery 和 GROUP BY 子句

BigQuery:聚合到不同的重复字段