Sql 合并bigquery中具有一个公共值的数组
在大查询中,我有一个表,其中一列是字符串数组。 数据如下所示:Sql 合并bigquery中具有一个公共值的数组,sql,arrays,google-bigquery,Sql,Arrays,Google Bigquery,在大查询中,我有一个表,其中一列是字符串数组。 数据如下所示: ['a','b'] ['b','c'] ['c', 'd'] ['e'] 现在我想要的输出是: ['a','b','c','d'] ['e'] 基本上我想合并所有至少有一个公共值的数组 我能做到吗 谢谢通常这种逻辑是使用所谓的递归CTE实现的,但是BigQuery不支持这种逻辑 幸运的是,最近引入的功能允许在BigQuery中实现这一点 下面是BigQuery标准SQL DECLARE rows_count, run_away_
['a','b']
['b','c']
['c', 'd']
['e']
现在我想要的输出是:
['a','b','c','d']
['e']
基本上我想合并所有至少有一个公共值的数组
我能做到吗
谢谢通常这种逻辑是使用所谓的递归CTE实现的,但是BigQuery不支持这种逻辑 幸运的是,最近引入的功能允许在BigQuery中实现这一点 下面是BigQuery标准SQL
DECLARE rows_count, run_away_stop INT64 DEFAULT 0;
CREATE TEMP TABLE ttt AS WITH input AS (
SELECT ['a', 'b'] arr UNION ALL
SELECT ['b', 'c'] UNION ALL
SELECT ['c', 'd'] UNION ALL
SELECT ['x', 'y'] UNION ALL
SELECT ['y', 'a'] UNION ALL
SELECT ['e']
)
SELECT ARRAY(SELECT val FROM UNNEST(arr) val ORDER BY val ) arr FROM input;
LOOP
SET rows_count = (SELECT COUNT(1) FROM ttt);
SET run_away_stop = run_away_stop + 1;
CREATE OR REPLACE TEMP TABLE ttt AS
SELECT ANY_VALUE(arr) arr FROM (
SELECT ARRAY(SELECT DISTINCT val FROM UNNEST(arr) val ORDER BY val) arr
FROM (
SELECT ANY_VALUE(arr1) arr1, ARRAY_CONCAT_AGG(arr) arr
FROM (
SELECT t1.arr arr1, t2.arr arr2, ARRAY(SELECT DISTINCT val FROM UNNEST(ARRAY_CONCAT( t1.arr, t2.arr)) val ORDER BY val) arr
FROM ttt t1, ttt t2
WHERE (SELECT COUNT(1) FROM UNNEST(t1.arr) val JOIN UNNEST(t2.arr) val USING(val)) > 0
) GROUP BY FORMAT('%t', arr1)
)
) GROUP BY FORMAT('%t', arr);
IF (rows_count = (SELECT COUNT(1) FROM ttt) AND run_away_stop > 1) OR run_away_stop > 10 THEN BREAK; END IF;
END LOOP;
SELECT ARRAY_TO_STRING(arr, ',') arr FROM ttt;
最终输出
Row arr
1 a,b,c,d,x,y
2 e
上面的步骤花了3次迭代。在现实生活中的例子中,它显然需要更多的时间——所以你需要调整允许的最大迭代次数——目前它是10次(见循环中的最后一条语句)
注意:以上最有可能是优化的-这取决于您通常这种类型的逻辑是使用所谓的递归CTE实现的,但BigQuery不支持这种逻辑 幸运的是,最近引入的功能允许在BigQuery中实现这一点 下面是BigQuery标准SQL
DECLARE rows_count, run_away_stop INT64 DEFAULT 0;
CREATE TEMP TABLE ttt AS WITH input AS (
SELECT ['a', 'b'] arr UNION ALL
SELECT ['b', 'c'] UNION ALL
SELECT ['c', 'd'] UNION ALL
SELECT ['x', 'y'] UNION ALL
SELECT ['y', 'a'] UNION ALL
SELECT ['e']
)
SELECT ARRAY(SELECT val FROM UNNEST(arr) val ORDER BY val ) arr FROM input;
LOOP
SET rows_count = (SELECT COUNT(1) FROM ttt);
SET run_away_stop = run_away_stop + 1;
CREATE OR REPLACE TEMP TABLE ttt AS
SELECT ANY_VALUE(arr) arr FROM (
SELECT ARRAY(SELECT DISTINCT val FROM UNNEST(arr) val ORDER BY val) arr
FROM (
SELECT ANY_VALUE(arr1) arr1, ARRAY_CONCAT_AGG(arr) arr
FROM (
SELECT t1.arr arr1, t2.arr arr2, ARRAY(SELECT DISTINCT val FROM UNNEST(ARRAY_CONCAT( t1.arr, t2.arr)) val ORDER BY val) arr
FROM ttt t1, ttt t2
WHERE (SELECT COUNT(1) FROM UNNEST(t1.arr) val JOIN UNNEST(t2.arr) val USING(val)) > 0
) GROUP BY FORMAT('%t', arr1)
)
) GROUP BY FORMAT('%t', arr);
IF (rows_count = (SELECT COUNT(1) FROM ttt) AND run_away_stop > 1) OR run_away_stop > 10 THEN BREAK; END IF;
END LOOP;
SELECT ARRAY_TO_STRING(arr, ',') arr FROM ttt;
最终输出
Row arr
1 a,b,c,d,x,y
2 e
上面的步骤花了3次迭代。在现实生活中的例子中,它显然需要更多的时间——所以你需要调整允许的最大迭代次数——目前它是10次(见循环中的最后一条语句)
注意:上面最有可能的情况是可以优化的-这取决于您这看起来像是您想要沿着图形中的路径走。在SQL中,通常使用递归CTE完成,而BQ不支持递归CTE,或者其他内置的功能,我也这么认为。使用递归查询就可以了。我只是想知道我们如何在BQ中做到这一点。。。谢谢你的洞察力。这看起来像是你想沿着图表中的路径走。在SQL中,通常使用递归CTE完成,而BQ不支持递归CTE,或者其他内置的功能,我也这么认为。使用递归查询就可以了。我只是想知道我们如何在BQ中做到这一点。。。谢谢你的洞察力。