通配符表和表列中的差异
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*.fooid
和 foo.*
缺少该字段。
但这不是 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.
这是有道理的——我说x
是NOT 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 年的数据,性能优势看起来很方便。以上是关于通配符表和表列中的差异的主要内容,如果未能解决你的问题,请参考以下文章