1

我的目标是测试由一个查询生成的 grp 是否与同一查询的输出相同。但是,当我更改单个变量名称时,会得到不同的结果。

下面我展示了一个相同查询的示例,我们知道结果是相同的。但是,如果您运行该组,您会发现一个查询产生的结果与另一个查询不同。

SELECT grp
FROM
(
  SELECT CONCAT(word, corpus) AS grp, rank1, rank2 
  FROM (
    SELECT
      word, corpus,
      ROW_NUMBER() OVER (PARTITION BY word ORDER BY test1 DESC) AS rank1,
      ROW_NUMBER() OVER (PARTITION BY word ORDER BY word_count DESC) AS rank2,
      ROW_NUMBER() OVER (PARTITION BY word ORDER BY corpus DESC) AS rank3,
      ROW_NUMBER() OVER (PARTITION BY word ORDER BY corpus_date DESC) AS rank4
    FROM 
    (
      SELECT *, (word_count * word_count * corpus_date) AS test1
      FROM [bigquery-public-data:samples.shakespeare]
    )
  )
)
WHERE rank1 <= 3 OR rank2 <= 3
HAVING grp NOT IN 
(
  SELECT grp FROM (
    SELECT CONCAT(word, corpus) AS grp, rank1, rank2
    FROM
    (
      SELECT
        word, corpus,
        ROW_NUMBER() OVER (PARTITION BY word ORDER BY test2 DESC) AS rank1,
        ROW_NUMBER() OVER (PARTITION BY word ORDER BY word_count DESC) AS rank2,
        ROW_NUMBER() OVER (PARTITION BY word ORDER BY corpus DESC) AS rank3,
        ROW_NUMBER() OVER (PARTITION BY word ORDER BY corpus_date DESC) AS rank4
      FROM 
      (
        SELECT *, (word_count * word_count * corpus_date) AS test2
        FROM [bigquery-public-data:samples.shakespeare]
      )
    )
  )
  WHERE rank1 <= 3 OR rank2 <= 3
)

更糟糕的是……现在,如果您尝试运行完全相同的查询,只是将变量名test1更改为test3,您将得到完全不同的结果。

SELECT grp
FROM
(
  SELECT CONCAT(word, corpus) AS grp, rank1, rank2 
  FROM (
    SELECT
      word, corpus,
      ROW_NUMBER() OVER (PARTITION BY word ORDER BY test3 DESC) AS rank1,
      ROW_NUMBER() OVER (PARTITION BY word ORDER BY word_count DESC) AS rank2,
      ROW_NUMBER() OVER (PARTITION BY word ORDER BY corpus DESC) AS rank3,
      ROW_NUMBER() OVER (PARTITION BY word ORDER BY corpus_date DESC) AS rank4
    FROM 
    (
      SELECT *, (word_count * word_count * corpus_date) AS test3
      FROM [bigquery-public-data:samples.shakespeare]
    )
  )
)
WHERE rank1 <= 3 OR rank2 <= 3
HAVING grp NOT IN 
(
  SELECT grp FROM (
    SELECT CONCAT(word, corpus) AS grp, rank1, rank2
    FROM
    (
      SELECT
        word, corpus,
        ROW_NUMBER() OVER (PARTITION BY word ORDER BY test2 DESC) AS rank1,
        ROW_NUMBER() OVER (PARTITION BY word ORDER BY word_count DESC) AS rank2,
        ROW_NUMBER() OVER (PARTITION BY word ORDER BY corpus DESC) AS rank3,
        ROW_NUMBER() OVER (PARTITION BY word ORDER BY corpus_date DESC) AS rank4
      FROM 
      (
        SELECT *, (word_count * word_count * corpus_date) AS test2
        FROM [bigquery-public-data:samples.shakespeare]
      )
    )
  )
  WHERE rank1 <= 3 OR rank2 <= 3
)

我想不出任何解释可以满足这两种奇怪的行为,这使我无法验证我的数据。有任何想法吗?

编辑

我已经按照响应建议的方式更新了 BigQuery SQL,并且出现了同样的不一致。

4

3 回答 3

2

问题是行编号的不确定性。

此表中有许多示例,其中(word_count * word_count * corpus_date)几个语料库是相同的。因此,当您 partition byword和 order bytest2时,用于分配行号的顺序是不确定的。

当您在同一个顶级查询中运行同一个子查询两次时,BigQuery 实际上会执行该子查询两次,并且由于这种不确定性,两次运行之间可能会产生不同的结果。

更改别名可能只是导致您的查询命中缓存,从而导致一组不同的不确定性选择和结果之间的不同重叠量。

ORDER BY您可以通过将分析函数中的子句更改为 include 来确认这一点corpus。例如,更改ORDER BY test2ORDER BY test2, corpus. 然后行编号将是确定性的,无论您使用什么别名,查询都将返回零结果。

于 2016-04-21T09:53:20.953 回答
1

我不明白这个问题。一般的 SQL 语法,特别是 BigQuery 都非常清楚:在 中定义的别名SELECT不能在SELECT其他表达式中使用。如BigQuery文档中所述:

子句中定义的别名可以在查询的、和子句中SELECT引用,但不能被 、或子句引用,也不能被同一子句中的其他表达式引用。[强调我的]GROUP BYHAVINGORDER BYFROMWHEREOMIT RECORD IFSELECT

因此,您的查询仅在test1test2test3是莎士比亚表中的列时才有效。没有理由认为这样的列会有相似的值,所以我不希望查询返回相同的结果。

编辑:

如果我们假设文档不正确,那么问题可能order byrow_number(). SQL 中的排序是不稳定的——这意味着具有相同排序键值的两行可以在排序过程中以任何顺序出现。即使是相同的查询也可以在两次运行中返回不同的结果。SQL 排序显然不稳定,因为表在行之间没有固有的排序(排序仅由列指定)。

因此,所发生的只是选择了具有相同排序键值的不同行。我认为这与别名无关。

你怎么能解决这个问题?在排序中添加一个附加排序键,例如id,作为最终键。或者使用rank()ordense_rank()并明确弄清楚如何处理重复项。

于 2016-04-20T19:41:28.243 回答
1

我注意到你总是提出棘手的问题,然后你很难接受甚至投票给答案。没关系!我想再试一次,所以让我们进入主题:

看起来在同一个 SELECT 语句中使用别名未记录且不受支持SELECT 子句文档中的以下注意事项:

每个表达式都可以通过在表达式后面添加一个空格和一个标识符来赋予一个别名。可以在表达式和别名之间添加可选的 AS 关键字以提高可读性。SELECT 子句中定义的别名可以在查询的 GROUP BY、HAVING 和 ORDER BY 子句中引用,但不能被 FROM、WHERE 或 OMIT RECORD IF 子句引用,也不能被同一 SELECT 子句中的其他表达式引用。

因此,这里有奇怪的行为而不会引发错误。因此,您可以自行承担使用它的风险,但最好不要(仍然很高兴听到 Google 团队的消息 - 但由于它不受支持 - 您可以期望没有太多信息可以解释这种行为)

同时 - 我建议只遵循支持的内容并将您的查询转换为低于“稳定”版本。
您在原始版本中遇到的问题没有问题!
(注意我在第一个子查询中更改了 WHERE 子句——否则它总是返回零行——这完全有意义)

SELECT grp
FROM
(
  SELECT CONCAT(word, corpus) AS grp, rank2, 
    ROW_NUMBER() OVER (PARTITION BY word ORDER BY [try_any_alias_1] DESC) AS rank1
  FROM (
    SELECT
      word, corpus,
      (word_count * word_count * corpus_date) AS [try_any_alias_1],
      ROW_NUMBER() OVER (PARTITION BY word ORDER BY word_count DESC) AS rank2,
      ROW_NUMBER() OVER (PARTITION BY word ORDER BY corpus DESC) AS rank3,
      ROW_NUMBER() OVER (PARTITION BY word ORDER BY corpus_date DESC) AS rank4
    FROM [bigquery-public-data:samples.shakespeare]
  )
)
WHERE rank1 <= 3 OR rank2 <= 4 // if rank2 <= 3 as in second subquery - result is always empty as expected
HAVING grp NOT IN 
(
  SELECT grp FROM (
    SELECT CONCAT(word, corpus) AS grp, rank2,
      ROW_NUMBER() OVER (PARTITION BY word ORDER BY [try_any_alias_2] DESC) AS rank1
    FROM
    (
      SELECT
        word, corpus,
        (word_count * word_count * corpus_date) AS [try_any_alias_2],
        ROW_NUMBER() OVER (PARTITION BY word ORDER BY word_count DESC) AS rank2,
        ROW_NUMBER() OVER (PARTITION BY word ORDER BY corpus DESC) AS rank3,
        ROW_NUMBER() OVER (PARTITION BY word ORDER BY corpus_date DESC) AS rank4
      FROM [bigquery-public-data:samples.shakespeare]
    )
  )
  WHERE rank1 <= 3 OR rank2 <= 3
)
于 2016-04-20T20:50:56.217 回答