Google BigQuery - 从选择语句执行动态生成的查询

Posted

技术标签:

【中文标题】Google BigQuery - 从选择语句执行动态生成的查询【英文标题】:Google BigQuery - Execute dynamically generated queries from a select statement 【发布时间】:2018-07-17 23:27:13 【问题描述】:

在 Google BigQuery 中有一个具有以下结构的巨大表(> 1 亿行):

name | departments
abc  | 1,2,5,6
xyz  | 4,5
pqr  | 3,4,6

想要将数据转换成以下格式:

name | 1 | 2 | 3 | 4 | 5 | 6
abc  | 1 | 1 |   |   | 1 | 1
xyz  |   |   |   | 1 | 1 |
pqr  |   |   | 1 | 1 |   | 1

截至目前,能够使用 CONCAT 和 REGEX_REPLACE 函数生成准备此格式数据集所需的查询:

    SELECT ' insert into dataset.output ( name, ' + 
  CONCAT(
      '_' , replace(departments,',',',_')  ) 
      
   + ' ) values(  \'' + name +'\','+ REGEXP_REPLACE(departments, "([^,\n]+)", "1") +')'
FROM (
select name, departments from dataset.input )

这会生成带有 100 M 插入查询的输出,这些查询可用于创建所需结构中的数据。

但是,下面是我的问题:

    我们是否可以使用 Big Query SQL 直接执行此查询的输出(100 M 插入查询),或者我们需要一个一个地触发每个插入?

    我相信没有办法旋转或转置具有多个逗号分隔值的列中的数据。对吗?

    有没有更优化的方法可以使用 BigQuery SQL 实现这一点,而不是编写自定义 Java 代码?

谢谢。

【问题讨论】:

【参考方案1】:

以下 BigQuery 标准 SQL 示例

#standardSQL
WITH `project.dataset.table` AS (
  SELECT 'abc' name, '1,2,5,6' departments UNION ALL
  SELECT 'xyz', '4,5' UNION ALL
  SELECT 'pqr', '3,4,6' 
)
SELECT 
  name,
  IF(departments LIKE '%1%', 1, 0) AS d1,
  IF(departments LIKE '%2%', 1, 0) AS d2,
  IF(departments LIKE '%3%', 1, 0) AS d3,
  IF(departments LIKE '%4%', 1, 0) AS d4,
  IF(departments LIKE '%5%', 1, 0) AS d5,
  IF(departments LIKE '%6%', 1, 0) AS d6
FROM `project.dataset.table`   

结果为

Row name    d1  d2  d3  d4  d5  d6   
1   abc     1   1   0   0   1   1    
2   xyz     0   0   0   1   1   0    
3   pqr     0   0   1   1   0   1    

因此,您需要在目的地上方运行到您准备的任何新表

注意,以上假设您只有 6 个部门,最重要的是数字没有歧义,例如 1 与 10 不冲突 如果你确实有这种情况 - 你需要在下面进行转换

  IF(departments LIKE '%2%', 1, 0) AS d2,

进入

  IF(CONCAT(',', departments, ',') LIKE '%,2,%', 1, 0) AS d2 ...

当然,您可以只使用一个简单的 INSERT 语句

INSERT `project.dataset.new_table` (name, d1, d2, d3, d4, d5, d6)    
SELECT 
  name,
  IF(departments LIKE '%1%', 1, 0) AS d1,
  IF(departments LIKE '%2%', 1, 0) AS d2,
  IF(departments LIKE '%3%', 1, 0) AS d3,
  IF(departments LIKE '%4%', 1, 0) AS d4,
  IF(departments LIKE '%5%', 1, 0) AS d5,
  IF(departments LIKE '%6%', 1, 0) AS d6
FROM `project.dataset.table`    

所以,这一切的最后一点是: 而不是为原始表中的每一行生成 INSERT STATEMENT - 您应该生成简单的 SELECT 语句来“旋转”

“极端”最小化生成代码的更新

看一个例子:

#standardSQL
CREATE TEMP FUNCTION c(departments STRING, department INT64) AS (
  IF(departments LIKE CONCAT('%',CAST(department AS STRING),'%'), 1, 0)
);
WITH `project.dataset.table` AS (
  SELECT 'abc' name, '1,2,5,6' departments UNION ALL
  SELECT 'xyz', '4,5' UNION ALL
  SELECT 'pqr', '3,4,6' 
), temp AS (
  SELECT name, departments AS d
  FROM `project.dataset.table`
)
SELECT 
name,
c(d,1)d1,
c(d,2)d2,
c(d,3)d3,
c(d,4)d4,
c(d,5)d5,
c(d,6)d6
FROM temp     

如您所见 - 现在您的 10000 行中的每一行都类似于 c(d,N)dN,,最大长度为 c(d,10000)d10000,,因此您有机会适应查询大小限制

【讨论】:

嗨,米哈伊尔,感谢您的及时回复。实际上,唯一部门 ID 的数量可以是 ~10000 。因此不确定我们是否可以在 JAVA 程序中动态生成此 SELECT 查询。对于如此大量的预期列,这种方法是否有任何限制? 您需要适应的列数和行大小有限制 据我们了解,Google BigQuery 最多支持 10000 列 我已经回答了一些关于动态生成数据透视查询的非常相似的问题——您应该在 SO 上进行搜索。只要你不超过限制 - 你应该是好的。注意:另一个限制是查询文本的大小。注意:10000 列绝对是非常极端的情况,听起来很可疑的设计 - 你可能想检查是否/为什么你甚至需要这样做 再次感谢米哈伊尔。如果有任何进一步的问题,将通过这些并回复。由于我们尝试服务的数据处理用例类型,我们需要这么多列。

以上是关于Google BigQuery - 从选择语句执行动态生成的查询的主要内容,如果未能解决你的问题,请参考以下文章

Google BigQuery:仅从最新表中选择

从 Google BigQuery 中的选择中排除数组类型字段

Google BigQuery 从 Python 脚本执行 SQL 文件

从 Google BigQuery 创建熊猫数据框时如何执行 na_values

从 Google 脚本将数据插入 BigQuery:遇到“”

从 Google BigQuery 中过滤或替换非英文字符