使用可重复使用的列别名

BigQuery 中的 GoogleSQL 支持可重复使用的列别名。借助可重复使用的列别名,您可以为 SQL 查询的 SELECT 子句中的表达式定义别名,并立即在同一 SELECT 列表或同一查询块的 WHERE 子句中引用该别名。

例如,以下查询展示了如何根据计算(例如 gross_price)过滤结果。您可以直接在 WHERE 子句中引用别名 gross_price,而无需在 WHERE 子句中重复计算或使用子查询:

SELECT
  net_price * 1.23 as gross_price
FROM
  product
WHERE
  gross_price < 10.0

可重复使用的列别名可为您提供以下优势:

  • 简化的 SQL 语法:您可以编写简洁明了的从左到右的 计算,而无需重复复杂的表达式或将查询封装在 子查询中。
  • 提高可读性:分析师和开发者可以声明一次表达式 ,然后立即重复使用。这让查询更容易阅读、调试和维护。

启用或停用可重复使用的列别名

默认情况下,可重复使用的列别名处于停用状态。如需使用列别名,您的 BigQuery 管理员必须使用以下数据定义语言 (DDL) 语句之一将 reusable_column_aliases_mode 选项设置为 on,以启用该功能:

如需设置此配置选项,您需要拥有 BigQuery Admin (roles/bigquery.admin) 角色,或者对项目拥有 bigquery.projects.update 权限,或者对组织拥有 bigquery.organizations.update 权限。 如需了解设置配置选项所需的权限,请参阅 所需权限 (位于“管理配置设置”页面)。

如需停用可重复使用的列别名,请将 reusable_column_aliases_mode 设置为 off。 如果您将该值设置为 NULL,系统会使用默认值,并且该功能也会停用。

示例

如需在组织级层启用可重复使用的列别名,请输入以下 DDL 语句:

ALTER ORGANIZATION
SET OPTIONS (
  `region-<code><var>REGION</var></code>.reusable_column_aliases_mode` = "on"
);

将 REGION 替换为您的区域。

如需在项目级层启用可重复使用的列别名,请输入以下 DDL 语句:

ALTER PROJECT <code><var>PROJECT_ID</var></code>
SET OPTIONS (
  `region-<code><var>REGION</var></code>.reusable_column_aliases_mode` = "on"
);

替换以下内容:

  • REGION:您的区域。
  • PROJECT_ID:您的项目 ID。

验证列别名是否已启用或停用

您可以通过查询以下信息架构视图来验证可重复使用的列别名是否已在项目或组织级层启用或停用:

如需详细了解如何使用信息架构视图,请参阅 简介 INFORMATION_SCHEMA。

如何使用可重复使用的列别名

您可以在 WHERE 子句或 SELECT 子句中使用别名(分配给表达式的标识符):

  • WHERE 子句:根据 SELECT 列表中定义的计算列进行过滤。
  • SELECT 子句:使用计算别名在同一投影列表中定义另一个别名,或确定查询返回的数据。

示例

此示例展示了如何使用可重复使用的列别名根据您之前在 SELECT 列表中定义的另一个计算来计算值。该查询还展示了如何在 WHERE 子句中引用别名:

SELECT
  net_price * 1.23 as gross_price,
  gross_price * 0.5 as discounted_gross_price
FROM
  product
WHERE
  discounted_gross_price < 10.0;

查询名称解析顺序中的行为变化(语义漂移)

标识符名称可以作为表中的物理列存在,也可以作为您创建的别名存在,因此您应考虑查询的名称解析顺序。 BigQuery 按以下顺序解析名称:

  1. 列名称:表中的现有列始终具有最高 优先级。
  2. 别名:查询中定义的别名。
  3. 外部查询列:父级查询中的列。
  4. 函数实参:如果它在用户定义的函数 (UDF) 或表值函数 (TVF) 中运行。
  5. 脚本变量:脚本中定义的变量。

根据此顺序,如果您的表有一个名为 gross_price 的列,并且您创建了一个名为 gross_price 的别名,则查询会使用列值,而不是您的别名。

这意味着,如果您有一个外部查询列、函数实参或脚本变量与您在 SELECT 子句中定义的别名同名,则 BigQuery 会使用别名 值进行计算,而不是变量或实参。

域名解析顺序的工作原理示例

以下示例展示了在存在命名冲突时,名称解析顺序如何使用可重复使用的列别名。

与外部查询列冲突

如果您未启用可重复使用的列别名,则在 SELECT 子句中定义的别名与外部查询中的列同名会导致使用外部查询列。启用可重复使用的列别名后,别名会在查询范围内“遮盖”外部查询列。

在以下示例中,嵌套查询使用别名,并且可以访问外部查询中的列:

SELECT
  name,
  net_price,
  category_id, -- table product has category_id column
  (SELECT 100 AS category_id -- alias defined with the same name
     FROM category c
     WHERE
       id = category_id  -- Now the alias category_id is used here, not the outer query column
  ) as X
FROM
  product;

如果您未启用可重复使用的列别名,则子查询会使用外部查询中 product 表的 category_id 列。因此,category_id 值因行而异。如果您启用可重复使用的列别名,则查询会对所有行使用别名值 100。

与函数实参冲突

如果查询在用户定义的函数 (UDF) 内运行,则在该查询中定义的别名优先于函数的实参。

在以下示例中,calculate_metric 函数有一个名为 val 的输入实参:

CREATE TEMP FUNCTION calculate_metric(val INT64) AS ((
  SELECT AS STRUCT
    5 AS val,       -- Alias defined as constant 5
    val + 10        -- Reference to 'val'
));

-- Calling the function with argument 100
SELECT calculate_metric(100);

如果您未启用可重复使用的列别名,则查询会使用传递给函数的实参值 (100),结果计算为110 (100 + 10)。如果您启用可重复使用的列别名,则查询会使用 SELECT列表中定义的别名 (5),结果计算为 15 (5 + 10)。

与脚本变量冲突

如果您未启用可重复使用的列别名,并且在 SELECT 子句中定义了一个别名,该别名与脚本变量同名,则会使用脚本变量。如果您启用可重复使用的列别名,则别名会在查询范围内遮盖变量。

以下示例声明了一个名为 gross_price 的变量,其默认值为 10.0。该查询还会计算列并将其别名为 gross_price:

DECLARE gross_price NUMERIC DEFAULT 10.0;

SELECT
  net_price * 1.23 AS gross_price,
  -- Usage of 'gross_price' here determines the behavior
  gross_price * 0.5 AS discounted_gross_price
FROM
  product;

如果您未启用可重复使用的列别名,则查询会使用变量值 10.0。结果是 discounted_gross_price 值 5.0,该值对于所有行都是常量。结果计算为 10.0 * 0.5 = 5.0。

如果您启用可重复使用的列别名,则查询会使用别名值 net_price * 1.23。结果是 discounted_gross_price 值,该值因行而异。结果计算为 (net_price * 1.23) * 0.5。

最佳实践

使用可重复使用的列别名时,请考虑以下最佳实践:

  • 在启用可重复使用的列别名之前,请评估其对现有工作负载的影响。
  • 为防止出现意外行为或静默行为变化(语义漂移),请勿使用脚本变量、函数实参或外部查询中的列的名称作为别名的名称。
  • 如果您要从支持别名 语义的源方言(例如 Teradata 或 Snowflake)迁移 SQL,请在开始迁移之前按照 SQL 转换说明 进行操作。

排查列别名问题

以下示例展示了如何排查可重复使用的列别名的常见问题。

问题:您获得意外的查询结果,或者别名似乎被忽略。

解决方法:验证名称解析顺序。如果您的表包含与别名同名的列,则列名称的优先级高于别名。为别名指定唯一名称,以避免此冲突。

错误: Column not found。

解决方法:确保您没有使用前向引用。您只能引用在使用之前定义的别名。这是从左到右进行评估的。

错误: Column name is ambiguous。

解决方法:确保别名名称在被引用之前未在同一 SELECT列表中定义多次。

限制

可重复使用的列别名受以下限制:

  • 当查询包含分组或聚合时,WHERE 子句中或作为聚合函数的实参不允许使用未聚合表达式(分组列或分组列的投影)的别名。在以下 查询中,别名 b 不正确地引用了包含 a 的表达式,而 是分组列:

    SELECT a+1 as b, sum(b) -- sum(b) is invalid.
    FROM t
    WHERE b > 5         -- Referencing b under WHERE clause is not allowed.
    GROUP BY a
    
  • 直接或间接引用聚合函数或窗口函数的别名不能在 WHERE 子句中使用,也不能作为其他聚合函数的实参使用。在以下查询中,别名 x 不正确地引用了聚合函数:

    SELECT sum(a) AS x, sum(x) -- sum(x) is invalid.
    FROM t
    WHERE x > 0          -- Referencing x under WHERE clause is not allowed.
    
  • 不允许对直接或间接引用另一个窗口函数的别名应用窗口函数。在以下查询中,别名 x 引用了无效的窗口函数:

    SELECT count(*) over() AS x, sum(x) over() -- sum(x) over() is invalid.
    FROM t
    
  • 管道语法不支持可重复使用的列别名。

  • Graph Query Language (GQL) 不支持可重复使用的列别名。