通配符表和表列中的差异

Posted

技术标签:

【中文标题】通配符表和表列中的差异【英文标题】:Wildcard tables and differences in table columns 【发布时间】:2018-03-29 14:35:45 【问题描述】:

我正在尝试使用 BigQuery 对使用 Wildcard Tables 的一系列表使用 JOIN

当通配符匹配的所有表都包含fooid (bar*.fooid) 列时,查询有效。但是,此列是最近添加的,当表通配符与字段不存在的表匹配时,查询会失败。

Error: Cannot read non-required field 'fooid' as required INT64. 

这是用于演示问题的查询的简化版本,它将从 foo 和 bar 中选择更多列。

SELECT foo.foo_id AS foo
FROM `bar.bar*` AS bar_alias
LEFT JOIN bar.foo_map foo ON (bar_alias.fooid = foo.foo_id)
WHERE (_TABLE_SUFFIX BETWEEN  '20170206' AND '20170208')

我查看了许多答案,包括 BigQuery IF field exists THEN,但看不到如何将它们与 JOIN 结合使用,或者当不知道没有该列的表时。

【问题讨论】:

您希望如何读取缺少的 REQUIRED 字段,就好像它存在一样? 我期待查询返回空值,因为 bar*.fooidfoo.* 缺少该字段。 但这不是 REQUIRED 的工作方式。一种选择是创建一个与字段为 NULLABLE 的后缀匹配的空表。如果那个用于确定如何读取其他匹配的表,您将得到 NULL 而不是错误。 好的,所以我将创建一个新表bar_empty 并使用bar* 执行UNION,您能否提供一个如何加入bar_empty 的方法? 答案有帮助吗? 【参考方案1】:

下面是一个示例,说明了这种情况是如何发生的,以及如何通过使用列/字段为 NULLABLE 的空表中的参考架构来修复它。假设我有以下两个表:

$ bq query --use_legacy_sql=false \
  "CREATE TABLE tmp_elliottb.bar20180328 (y STRING) AS SELECT 'bar';"

$ bq query --use_legacy_sql=false \
  "CREATE TABLE tmp_elliottb.bar20180329 " \
  "(x INT64 NOT NULL, y STRING) AS SELECT 1, 'foo';"

x 在第二个表中具有NOT NULL 属性,但第一个表中缺少该列。尝试使用表通配符时出现错误:

$ bq query --use_legacy_sql=false \
  "SELECT * FROM \`tmp_elliottb.bar*\` " \
  "WHERE _TABLE_SUFFIX BETWEEN '20180301' AND '20180329';"
Waiting on <job id> ... (0s) Current status: DONE   
Error in query string: Error processing job '<job id>': Cannot read non-required field 'x' as required INT64.
Failure details:
- query: Cannot read non-required field 'x' as required INT64.

这是有道理的——我说xNOT NULL,但bar20180328 表没有列。现在,如果我创建一个与 * 扩展匹配的新表,但该列没有 NOT NULL

$ bq query --use_legacy_sql=false \
  "CREATE TABLE tmp_elliottb.bar_empty (x INT64, y STRING);"
$ bq query --use_legacy_sql=false \
  "SELECT * FROM \`tmp_elliottb.bar*\` " \
  "WHERE _TABLE_SUFFIX BETWEEN '20180301' AND '20180329';"
...
+------+-----+
|  x   |  y  |
+------+-----+
|    1 | foo |
| NULL | bar |
+------+-----+

我得到的是结果而不是错误。例如,在您的情况下,您需要使用名为 bar_empty 的预期架构创建一个表,但其他表缺少的字段/列都没有 NOT NULL 属性。

话虽如此,如果可能的话,我强烈建议使用分区表。除了其他好处之外,分区表更易于使用,因为它们在所有时间都具有一致的架构。

【讨论】:

谢谢,这行得通。我认为这是可行的,因为bar* 首先匹配所有表,然后WHERE _TABLE_SUFFIX BETWEEN 限制和排除bar_empty。我将看看分区表,但我正在处理 2-3 年的数据,性能优势看起来很方便。

以上是关于通配符表和表列中的差异的主要内容,如果未能解决你的问题,请参考以下文章

通配符

SQL的通配符

SQL Server:SQL 通配符

SQL基本操作——通配符

sql语句中通配符有几种

尚不支持 BigQuery、非分区表上的通配符表和基于字段的分区表