【问题标题】:How to refer to another field computed in the WHERE clause?如何引用 WHERE 子句中计算的另一个字段?
【发布时间】:2020-01-31 14:45:12
【问题描述】:

考虑一个简化的例子:

SELECT
  lengthy_expression AS a,
  g(a) AS b,
  h(a) AS c,
  ...
FROM
  my_table

这里,lengthy_expression 表示一个复杂的表达式,它使用来自my_table 的多个字段并跨越多行。其结果用于计算另外两个字段bc。但是,在标准SQL中是不允许的,因为WHERE子句中的表达式不允许引用WHERE子句中另一个表达式的结果(为什么不超出我的范围)。

天真的选项是重复lengthy_expression,但这是我明确想要避免的。

一种选择是使用子查询:

SELECT
  a,
  g(a) AS b,
  h(a) AS c,
  ...
FROM (
  SELECT
    lengthy_expression AS a,
    ...
  FROM
    my_table
)

但正如您所见,我现在需要重复外部查询所需的其他字段 ...

也许是一个带有连接的子查询?

SELECT
  a,
  g(a) AS b,
  h(a) AS c,
  ...
FROM
  my_table
INNER JOIN (
  SELECT
    lengthy_expression AS a
  FROM
    my_table
) USING id

它可以工作,但是现在有一个(可能很昂贵的)连接,除了保持查询可读性之外没有其他用途。而且它甚至不能很好地达到这个目的,因为lengthy_expression 被隐藏在使用它的位置下方,人类读者必须跳遍整个地方才能找出发生了什么。

另一种方法是使用 CTE:

WITH
my_table_with_a AS (
  SELECT
    *,
    lengthy_expression AS a
  FROM
    my_table
)
SELECT
  *,
  g(a) AS b,
  h(a) AS c,
  ...
FROM
  my_table_with_a

至少现在阅读顺序或多​​或少与操作发生的逻辑顺序相匹配,但它非常冗长,并且很难为my_table_with_a 找到一个好名字。尤其是因为在实践中,我会重复这种模式两到三遍。

有没有更好的方法来做到这一点?

【问题讨论】:

  • 我会使用 CTE。您说它们很冗长,但是与复杂/重复的联接相比,新的代码行相对“便宜”。如果同事(或 6 个月后的您)需要审查您的代码,CTE 的可读性非常好。

标签: sql google-bigquery


【解决方案1】:

以下是 BigQuery 标准 SQL

#standardSQL
SELECT 
  a,
  g(a) AS b,
  h(a) AS c,
FROM `project.dataset.my_table`,
UNNEST([lengthy_expression]) a   

以下是上述方法的极其简化的示例

#standardSQL
WITH `project.dataset.my_table` AS (
  SELECT 1 x, 2 y, 3 z UNION ALL
  SELECT 4, 5, 6
)
SELECT 
  a,
  a / 2 AS b,
  2 * a AS c
FROM `project.dataset.my_table`,
UNNEST([x + y + z]) a   
WHERE a > 10    

结果

Row a   b   c    
1   15  7.5 30   

注意:如果 lengthy_expression 的结果本身是一个 ARRAY - 您需要将其包含在结构中,因为 BigQuery 不支持数组数组

【讨论】:

  • 哈,这是一个非常有趣的 hack,谢谢!知道这是否比子查询或 CTE 方法具有更好/更差的性能?
  • 我不希望这里有任何性能影响 - 但显然不那么冗长且更易于维护
【解决方案2】:

只需使用*:

SELECT a, g(a) AS b, h(a) AS c, ...
FROM (SELECT lengthy_expression AS a, t.*
      ...
      FROM my_table t
     ) t

我很确定 BigQuery 不会为查询实际未使用的字段向您收费。

【讨论】:

  • 确实如此,即使使用 CTE,未使用的字段也会被优化掉。尽管如此,我还是觉得这种风格相当难以理解,尤其是当你开始嵌套它们时(d 取决于 c 取决于 b 取决于 a)。
  • @Thomas 。 . .这可以满足您的需求。我不确定您所说的“不可读”是什么。不重用列别名解决了两个问题:(1)它消除了别名和列同名时的歧义; (2) 它使列表达式可以独立评估(即select 中没有评估顺序。
猜你喜欢
  • 2011-04-22
  • 1970-01-01
  • 1970-01-01
  • 2011-01-24
  • 2019-03-06
  • 2011-10-25
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多