如果一个数组包含使用 BigQuery 的另一个数组的所有值,我如何过滤行?

Posted

技术标签:

【中文标题】如果一个数组包含使用 BigQuery 的另一个数组的所有值,我如何过滤行?【英文标题】:How can I filter rows if one array contains all values from another array using BigQuery? 【发布时间】:2020-10-20 18:08:24 【问题描述】:

我需要从 BigQuery 中的表中获取特定数组。然后,如果分区窗口中的某个数组已经具有当前数组的所有值和其他一些值,我想减少行。

with t0 as (SELECT 1 as big_id, '101' as small_id,  0.99 as bottom, 1.03 top
      UNION ALL SELECT 1, '102', 1.05, 1.09
      UNION ALL SELECT 1, '103', 1.09, 1.13
      UNION ALL SELECT 1, '104', 1.2, 1.25
      UNION ALL SELECT 1, '105', 1.33, 1.39
      UNION ALL SELECT 2, '102', 1.05, 1.09
      UNION ALL SELECT 2, '103', 1.09, 1.13
      UNION ALL SELECT 2, '104', 1.2, 1.25
      UNION ALL SELECT 2, '105', 1.33, 1.39)
SELECT t0.big_id, row_number() OVER (PARTITION BY t0.big_id) group_id, ARRAY_AGG(t1.small_id) my_arrays FROM t0
CROSS JOIN t0 t1

WHERE t0.big_id = t1.big_id AND t1.top/t0.bottom BETWEEN 1 AND 1.15
GROUP BY t0.big_id, t0.small_id

我有一个表格,其中包含 id 以及置信区间的顶部和底部。我想比较从small_id 开始的所有独特的small_id 对与底部底部。 唯一对意味着:如果101 and 102 已经比较,则不需要比较102 and 101。 然后我需要将具有相似置信区间的small_ids 分组到数组中。 然后,如果所有 id 在同一分区窗口中的某个更大组中匹配,则我需要减少组。 small_id 不是数字。只是文本字符串。因此无法使用 直接将 small_id 比较为数字。

我需要减少这些行,因为我在另一个数组中获得了值

我需要如何修改我的查询以获得预期的输出?

【问题讨论】:

所有这些十字和箭头确实没有帮助 - 请澄清您在普通视图中的预期结果以及您尝试在查询中实现的逻辑是什么 感谢您的回复!我添加了更多预期结果的细节 【参考方案1】:

以下是 BigQuery 标准 SQL

#standardsql
with t0 as (SELECT 1 as big_id, '101' as small_id,  0.99 as bottom, 1.03 top
  UNION ALL SELECT 1, '102', 1.05, 1.09
  UNION ALL SELECT 1, '103', 1.09, 1.13
  UNION ALL SELECT 1, '104', 1.2, 1.25
  UNION ALL SELECT 1, '105', 1.33, 1.39
  UNION ALL SELECT 2, '102', 1.05, 1.09
  UNION ALL SELECT 2, '103', 1.09, 1.13
  UNION ALL SELECT 2, '104', 1.2, 1.25
  UNION ALL SELECT 2, '105', 1.33, 1.39
), temp as (      
  SELECT t0.big_id, 
    row_number() OVER (PARTITION BY t0.big_id) group_id, 
    ARRAY_AGG(t1.small_id) my_arrays FROM t0
  CROSS JOIN t0 t1
  WHERE t0.big_id = t1.big_id AND t1.top/t0.bottom BETWEEN 1 AND 1.15
  GROUP BY t0.big_id, t0.small_id
)
select big_id, group_id, any_value(my_arrays) my_arrays 
from (
  select t1.*,
    ( select count(1)
      from t1.my_arrays id
      join t2.my_arrays id
      using(id)
      where t1.group_id != t2.group_id
    ) = array_length(t1.my_arrays) as flag
  from temp t1 
  join temp t2
  using (big_id)
)
group by big_id, group_id
having countif(flag) = 0     

有输出

【讨论】:

很高兴它对你有用。最初我认为它纯粹是基于递归的逻辑,可以通过脚本或 js udf 来解决。但是经过一段时间的睡眠并意识到它可以以基于集合的方式完成 - 所以,我们开始吧:o) 谢谢。它看起来比js好多了。使用 js udf 我们会失去什么? 通常您希望将您的逻辑转换为基于集合的方式,这样您就可以使用最有效的纯 SQL!如果这是不可能的,那么当您寻找有一些限制的脚本或 js udf 时。所以要回答“我们正在失去什么”,我会说 - 基于集合的操作的有效性

以上是关于如果一个数组包含使用 BigQuery 的另一个数组的所有值,我如何过滤行?的主要内容,如果未能解决你的问题,请参考以下文章

树状数组的另一种用法(离散化存数)

如果第一个条件失败,则在具有较少条件的另一列上进行 SQL 连接

Bigquery - 数组索引 5 超出范围

使一个数组等于特定对象的另一个数组

根据另一列中的值更新 BigQuery 中的嵌套数组

如何关联多个 BigQuery 数组字段?