Google bigquery 当使用与重复字段同名的字段时,BigQuery将变平

Google bigquery 当使用与重复字段同名的字段时,BigQuery将变平,google-bigquery,Google Bigquery,编辑以使用公共数据集 我有一个具有以下模式的表,您可以在此处访问该表: 如果我运行以下查询,我会得到cnt1与cnt2的不同结果 如果从where子句中删除tc别名,则两个计数的结果相同: SELECT COUNT(*) AS cnt1, COUNT(dr_id) as cnt2, FROM (SELECT * FROM rs_public.test_count) AS tc WHERE is_published 但是,如果我重复第一个查询,但在where子句中使用is_cla

编辑以使用公共数据集

我有一个具有以下模式的表,您可以在此处访问该表:

如果我运行以下查询,我会得到cnt1与cnt2的不同结果

如果从where子句中删除tc别名,则两个计数的结果相同:

SELECT 
  COUNT(*) AS cnt1,
  COUNT(dr_id) as cnt2,
FROM (SELECT * FROM rs_public.test_count) AS tc
WHERE
  is_published
但是,如果我重复第一个查询,但在where子句中使用is_claished字段,我将再次获得相同的计数

SELECT 
  COUNT(*) AS cnt1,
  COUNT(dr_id) as cnt2,
FROM (SELECT * FROM rs_public.test_count) AS tc
WHERE
  tc.is_claimed
我认为这是一个bug,BigQuery正在变得混乱,因为is_published是cover_photos记录的一个外部字段,也是一个叶子字段。在评估是否应展平结果时,错误地使用了cover_photos.is_published字段,但在根据where子句筛选结果时使用了outer is_published字段

下面是一个不使用select*的反例,我在下面对Felipe答案的评论中引用了该反例:

SELECT
  COUNT(*)
FROM (
  SELECT
    dr_id,
    cover_photos.is_published
  FROM
    [realself-main:rs_public.test_count] )
返回3

SELECT
  COUNT(*), COUNT(0)
FROM (
  SELECT
    dr_id,
    cover_photos.is_published
  FROM
    [realself-main:rs_public.test_count] )

返回7和3!根据我的评论,似乎唯一安全的选择是永远不要使用count*

如果查询可以以多种方式解释,BigQuery将尽最大努力猜测您的意图——有时会产生不一致的结果。每一个数据库都是如此,因为SQL为这些模糊性留出了空间

解决方案:消除查询中的歧义-可能两个结果都是正确的,这取决于您试图计算的内容

通过不使用*,并使前缀显式来消除歧义,同时您也可以显式请求表的展平方式


我真的很想对您的具体数据和结果发表评论,但鉴于您尚未提供公开样本,我无法发表评论

感谢分享数据集@alan!让我们看看它的样子:

这是一个有趣的表:它有3列3行,但很小,是一个普通的SQL表。有趣的是,第三列可以承载嵌套记录。在第一行,它没有空值,第二行只有1个值,第三行嵌套了5个不同的值

当您开始按列计数时,事情会变得有趣:

SELECT COUNT(*) 
FROM [realself-main:rs_public.test_count]
3
这很有意义,数据集有3行

SELECT COUNT(dr_id) 
FROM [realself-main:rs_public.test_count]
3
这也是有道理的,有3个dr_id

SELECT COUNT(cover_photos.is_published) 
FROM [realself-main:rs_public.test_count]
6
现在事情变得更有趣了。它是6,因为封面照片有6个值。如果发布了,空值不算

SELECT COUNT(cover_photos.is_published), COUNT(dr_id)
FROM [realself-main:rs_public.test_count]
6   3
这仍然是有道理的:6张封面照片已经出版,3张医生身份证

SELECT COUNT(*) 
FROM (
  SELECT cover_photos.is_published, dr_id
  FROM [realself-main:rs_public.test_count]
)
3
这也很有趣:如果我们进行子查询,COUNT*将查看返回的行数。返回了3行。这仍然是有道理的

但是:

SELECT COUNT(*), COUNT(cover_photos.is_published)
FROM (
  SELECT cover_photos.is_published, dr_id
  FROM [realself-main:rs_public.test_count]
)
7   6   
7和6。七为什么是7

好吧,BigQuery必须为子查询选择一种扁平化策略。看看我贴在那里的那张桌子,你能看到它有7行吗?这是统计的七行

让我们明确地看一下它们:

SELECT dr_id, cover_photos.is_published
FROM (
  SELECT cover_photos.is_published, dr_id
  FROM [realself-main:rs_public.test_count]
)
看到了吗?那是七排。选择具有嵌套记录的行是BigQuery的一个很好的特性,BigQuery有时需要展平数据以处理某些查询。前2行被展平为正好2行,其中一行带有封面照片。发布为空,第3行被展平为5行,每个封面照片一行。发布为空

这个故事的寓意是在处理嵌套数据时要小心:有些查询会以用户无法预料的方式将其展平,但这对计算机在试图做出决定时很有意义

根据要求,让我们深入了解:

看看这两个查询之间的区别:

SELECT COUNT(*)
FROM (
  SELECT *
  FROM (
    SELECT * FROM [realself-main:rs_public.test_count]  
    WHERE is_published
  ) 
)

SELECT COUNT(*)
FROM (
  SELECT *
  FROM (
    SELECT * FROM [realself-main:rs_public.test_count]  
  ) 
)
WHERE is_published
在查看结果之前,您能猜出每个查询将给出什么结果吗?不,你不能。这两个查询都是不明确的,因此为了得到答案,BigQuery需要进行一些猜测和优化

第一个查询的结果是7,第二个查询的结果是3。去试试看

有什么区别?从这些查询的结果可以看出,在第二个查询中,BigQuery看到您感兴趣的唯一列是“is_published”,因此它优化了树,以便只读取该列。但是BigQuery很难优化第一个查询-因此它猜测他们可能真的想要*,并且*意味着我需要在将表传递到下一层之前将其展平。它压平了表,因此稍后最上面的查询将看到7行


这些结果有保证吗?否-查询不明确。如何减少歧义?不要使用SELECT*,而是告诉BigQuery您要查找哪些列-这样它就不需要为您猜测了。

我正在添加一个新的答案,因为您一直在向问题添加元素-它们都应该得到不同的答案

您说这个查询让您感到惊讶:

SELECT COUNT(*), COUNT(0)
FROM (
  SELECT dr_id, cover_photos.is_published
  FROM [realself-main:rs_public.test_count] )
你会感到惊讶,因为结果是7和3

如果我尝试以下方法,也许会有意义:

SELECT COUNT(*), COUNT(0), 
       GROUP_CONCAT(STRING(cover_photos.is_published)),
       GROUP_CONCAT(STRING(dr_id)), 
       GROUP_CONCAT(IFNULL(STRING(cover_photos.is_published),'null')),
       GROUP_CONCAT("0")
FROM (
  SELECT dr_id, cover_photos.is_published
  FROM [realself-main:rs_public.test_count] 
)
看到了吗?这是同一个查询,加上相同子列的4个不同聚合,其中一个由嵌套的重复数据组成,并且其中还有一个空值 一排

查询结果如下:

7   3   1,1,1,0,0,0 1234,4321,9999  null,1,1,1,0,0,0    0,0,0
如第5列所示,7来自于将嵌套数据完全扩展为7行。从第6列可以看出,3来自于仅对0进行三次评估



这些微妙之处都与处理嵌套的重复数据有关。我建议您不要使用嵌套重复数据,直到您准备好接受在使用嵌套重复数据时可能会发生这些微妙的情况。

我也有同样的问题,但尽管设置了赏金,但我没有设法得到解决此类查询的准确度的答案。。。谢谢你链接到这个问题,@oulenz!这正是我想指出的@alan问这个新问题的地方,但我找不到。对于你提出的问题,我最后的评论仍然是:对于一般问题,你已经得到了我的一般答案。要得到具体的答案,你需要问一个具体的问题。有关SQL基础知识,请参阅此答案中链接的文章。我相信,如果你能提供让我们走到这一步的数据,我可以做得更多。我知道我是jr。用你的话来说,扁平化意味着什么?当我想到扁平化时,我想到去规范化。我认为你的最后一个例子是至关重要的。如果子选择是真正平坦的,count0和count*都应该为7。我们需要的是一个解释,说明两者的计算方式到底有什么不同。我仍然不明白你怎么能说这些查询是不明确的。它们不是,两者都是确定性的。问题是它们是如何解决的,以及为什么它们的解决方式不同。在我看来,第一个查询的结果完全是错误的。如果dr_id是唯一的列,count*和countdr_id应始终给出相同的结果。通常,count*应始终给出与count0相同的结果。如果BigQuery团队不同意,它应该记录如何解析count*。在那之前,伯爵是没用的。如果你给我一个我可以查看的数据集,我可以查看并评论特定的数据集。顺便说一句,我没有说不要使用count*,混乱是我的错,因为我没有说不太含糊的不要使用select*,我为错误引用您道歉。尽管如此,只要结果不可预测,就不能使用count*。@FelipeHoffa我编辑我的问题是为了使用我创建的公共数据集。我认为这将使我看到的具体问题更加清晰。另外值得注意的是,我的许多查询都是由Looker生成的,因此,了解这些查询不起作用的具体原因对我来说很重要。@MichaelSheldon,但查询中的is_published I引用不会重复;这是重复的封面照片。我认为BigQuery对这个问题感到困惑,需要清楚的解释,但它并没有完全回答这个问题。你能解释一下为什么我的查询1和查询3返回不同的结果吗?它们都没有明确引用重复字段,where子句中的非重复字段is_声明和is_发布对于每一行都是正确的。我添加了更多文本,请告诉我这样是否更好。谢谢。这个故事的寓意似乎是不要将count*与select*子查询一起使用。我仍然不明白为什么在我的第一个查询中将is_发布替换为is_声明会得到不同的结果。。。但我认为你的论点是,这些查询是不明确的,所以你不应该试图分析结果。我想,这可能值得添加到文档中——或者,在理想情况下,对于您认为不明确的查询,您可能会返回一个错误而不是结果。实际上,我发现了一个反例,count即使没有select*,也会给出奇怪的结果。我将这些添加到我的问题中,因为评论中的格式不起作用。似乎安全的选择是不使用count。有什么意见吗,@FelipeHoffa?谢谢你的支持。我喜欢GROUP_CONCAT技巧来探索这里发生了什么,但我感到困惑的是,为什么向查询中添加COUNT0会将COUNT的结果从3更改为7。如果COUNT应该返回查询中重复次数最多的字段的COUNT,而COUNT0返回完整记录的数量,那么为什么向查询中添加COUNT0会更改COUNT*的值?这是一个有点学术性的讨论,因为我不太可能在一个查询中使用两个计数指标,但我很想更好地理解这一点。嗨,艾伦-塞德注意:你与这次发布有关吗。很棒的博客文章,在这里庆祝这个消息:我不为Looker工作,但我是一个热情的客户。。。这是一个伟大的产品,他们当然包括一些戳嵌套记录的微妙之处。我想知道-您是否看到嵌套记录在其他地方实现,它们的行为如何?
7   3   1,1,1,0,0,0 1234,4321,9999  null,1,1,1,0,0,0    0,0,0