名称解析

适用于:check marked yes Databricks SQL check marked yes Databricks Runtime

名称解析是将标识符解析为特定列、字段、参数或表引用的过程。

列、字段、参数和变量解析

表达式中的标识符可以是对以下任一项的引用:

  • 基于视图、表、通用表表达式 (CTE) 的列名称,或者 column_alias
  • 结构或映射中的字段名称或映射键。 永远不会取消限定字段和键。
  • SQL 用户定义的函数参数名称
  • 变量名称
  • 一个不需要使用 () 的特殊函数,例如 current_usercurrent_date
  • INSERTUPDATEMERGESET VARIABLE 的上下文中用于将列或变量值设置为其默认值的 DEFAULT 关键字。

名称解析应用以下原则:

  • 最接近的匹配引用优先,并且
  • 列和参数优先于字段和键。

具体而言,标识符到特定引用的解析按顺序遵循以下规则:

  1. 局部引用

    1. 列引用

      将可能已限定的标识符与 FROM clause表引用中的列名称进行匹配。

      如果存在多个此类匹配项,则引发 AMBIGUOUS_COLUMN_OR_FIELD 错误。

    2. 无参数函数引用

      如果标识符未限定并且与 current_usercurrent_datecurrent_timestamp 匹配:则将其解析为以下函数之一。

    3. 列默认规范

      如果标识符未限定、与 default 匹配并且在 UPDATE SETINSERT VALUESMERGE WHEN [NOT] MATCHED 的上下文中构成了完整表达式:则解析为 INSERTUPDATEMERGE 的目标表的相应 DEFAULT 值。

    4. 结构字段或映射键引用

      如果标识符已限定,则根据以下步骤尝试将它与字段或映射键进行匹配:

      A. 删除最后一个标识符,并将其视为字段或键。 B. 将余下部分与 FROM clause表引用中的列进行匹配。

      如果存在多个此类匹配项,则引发 AMBIGUOUS_COLUMN_OR_FIELD 错误。

      如果存在匹配项并且列为:

      • STRUCT:匹配字段。

        如果无法匹配字段,则引发 FIELD_NOT_FOUND 错误。

        如果存在多个字段,则引发 AMBIGUOUS_COLUMN_OR_FIELD 错误。

      • MAP:如果键已限定,则引发错误。

        如果映射中实际不存在该键,则可能会出现运行时错误。

      • 任何其他类型:引发错误。 C. 重复上述步骤以删除作为字段的尾部标识符。 应用规则 (A) 和 (B),同时保留一个解释为列的标识符。

  2. 横向列别名

    适用于:check marked yes Databricks SQL check marked yes Databricks Runtime 12.2 及更高版本

    如果表达式位于 SELECT 列表中,则将前导标识符与该 SELECT 列表中的上一列别名进行匹配。

    如果存在多个此类匹配项,则引发 AMBIGUOUS_LATERAL_COLUMN_ALIAS 错误。

    将余下的每个标识符作为字段或映射键进行匹配,如果无法匹配,则引发 FIELD_NOT_FOUNDAMBIGUOUS_COLUMN_OR_FIELD 错误。

  3. 相关性

    • LATERAL

      如果查询的前面带有 LATERAL 关键字,则应用规则 1.a 和 1.d,同时考虑 FROM 中包含该查询和 LATERAL 前面部分的表引用。

    • 常规

      如果查询是标量子查询INEXISTS 子查询,则应用规则 1.a、1.d 和 2,同时考虑包含查询的 FROM 子句中的表引用。

  4. 嵌套关联

    重新应用规则 3 并迭代查询的嵌套级别。

  5. 例程参数

    如果表达式是 CREATE FUNCTION 语句的一部分:

    1. 将标识符与参数名称进行匹配。 如果标识符已限定,则限定符必须与函数的名称匹配。
    2. 如果标识符已限定,则遵循规则 1.c 与参数的字段或映射键进行匹配
  6. 变量

    1. 将标识符与变量名称匹配。 如果标识符已限定,则限定符必须是 sessionsystem.session
    2. 如果标识符已限定,则遵循规则 1.c 与变量的字段或映射键进行匹配

限制

为了防止执行资源开销可能很高的关联查询,Azure Databricks 将支持的关联限制为一个级别。 此限制也适用于 SQL 函数中的参数引用。

示例

-- Differentiating columns and fields
> SELECT a FROM VALUES(1) AS t(a);
 1

> SELECT t.a FROM VALUES(1) AS t(a);
 1

> SELECT t.a FROM VALUES(named_struct('a', 1)) AS t(t);
 1

-- A column takes precendece over a field
> SELECT t.a FROM VALUES(named_struct('a', 1), 2) AS t(t, a);
 2

-- Implict lateral column alias
> SELECT c1 AS a, a + c1 FROM VALUES(2) AS T(c1);
 2  4

-- A local column reference takes precedence, over a lateral column alias
> SELECT c1 AS a, a + c1 FROM VALUES(2, 3) AS T(c1, a);
 2  5

-- A scalar subquery correlation to S.c3
> SELECT (SELECT c1 FROM VALUES(1, 2) AS t(c1, c2)
           WHERE t.c2 * 2 = c3)
    FROM VALUES(4) AS s(c3);
 1

-- A local reference takes precedence over correlation
> SELECT (SELECT c1 FROM VALUES(1, 2, 2) AS t(c1, c2, c3)
           WHERE t.c2 * 2 = c3)
    FROM VALUES(4) AS s(c3);
  NULL

-- An explicit scalar subquery correlation to s.c3
> SELECT (SELECT c1 FROM VALUES(1, 2, 2) AS t(c1, c2, c3)
           WHERE t.c2 * 2 = s.c3)
    FROM VALUES(4) AS s(c3);
 1

-- Correlation from an EXISTS predicate to t.c2
> SELECT c1 FROM VALUES(1, 2) AS T(c1, c2)
    WHERE EXISTS(SELECT 1 FROM VALUES(2) AS S(c2)
                  WHERE S.c2 = T.c2);
 1

-- Attempt a lateral correlation to t.c2
> SELECT c1, c2, c3
    FROM VALUES(1, 2) AS t(c1, c2),
         (SELECT c3 FROM VALUES(3, 4) AS s(c3, c4)
           WHERE c4 = c2 * 2);
 [UNRESOLVED_COLUMN] `c2`

-- Successsful usage of lateral correlation with keyword LATERAL
> SELECT c1, c2, c3
    FROM VALUES(1, 2) AS t(c1, c2),
         LATERAL(SELECT c3 FROM VALUES(3, 4) AS s(c3, c4)
                  WHERE c4 = c2 * 2);
 1  2  3

-- Referencing a parameter of a SQL function
> CREATE OR REPLACE TEMPORARY FUNCTION func(a INT) RETURNS INT
    RETURN (SELECT c1 FROM VALUES(1) AS T(c1) WHERE c1 = a);
> SELECT func(1), func(2);
 1  NULL

-- A column takes precedence over a parameter
> CREATE OR REPLACE TEMPORARY FUNCTION func(a INT) RETURNS INT
    RETURN (SELECT a FROM VALUES(1) AS T(a) WHERE t.a = a);
> SELECT func(1), func(2);
 1  1

-- Qualify the parameter with the function name
> CREATE OR REPLACE TEMPORARY FUNCTION func(a INT) RETURNS INT
    RETURN (SELECT a FROM VALUES(1) AS T(a) WHERE t.a = func.a);
> SELECT func(1), func(2);
 1  NULL

-- Lateral alias takes precedence over correlated reference
> SELECT (SELECT c2 FROM (SELECT 1 AS c1, c1 AS c2) WHERE c2 > 5)
    FROM VALUES(6) AS t(c1)
  NULL

-- Lateral alias takes precedence over function parameters
> CREATE OR REPLACE TEMPORARY FUNCTION func(x INT)
    RETURNS TABLE (a INT, b INT, c DOUBLE)
    RETURN SELECT x + 1 AS x, x
> SELECT * FROM func(1)
  2 2

-- All together now
> CREATE OR REPLACE TEMPORARY VIEW lat(a, b) AS VALUES('lat.a', 'lat.b');

> CREATE OR REPLACE TEMPORARY VIEW frm(a) AS VALUES('frm.a');

> CREATE OR REPLACE TEMPORARY FUNCTION func(a INT, b int, c int)
  RETURNS TABLE
  RETURN SELECT t.*
    FROM lat,
         LATERAL(SELECT a, b, c
                   FROM frm) AS t;

> VALUES func('func.a', 'func.b', 'func.c');
  a      b      c
  ----- -----  ------
  frm.a  lat.b  func.c

表和视图解析

表引用中的标识符可以是以下任一标识符:

  • Unity Catalog 或 Hive 元存储中的持久表或视图
  • 公用表表达式 (CTE)
  • 临时视图

标识符的解析方式取决于它是否已限定:

  • Qualified

    如果标识符包含三个部分且已完全限定:catalog.schema.relation,则它是唯一的。

    如果标识符由两个部分组成:schema.relation,则使用 SELECT current_catalog() 的结果进一步限定该标识符以使其保持唯一。

  • 未限定

    1. 通用表表达式

      如果引用在 WITH 子句的范围内,则将标识符与某个 CTE 进行匹配,该 CTE 从直接包含的 WITH 子句开始,并从该子句外移。

    2. 临时视图

      将标识符与当前会话中定义的任何临时视图进行匹配。

    3. 永久性表

      通过在前面添加 SELECT current_catalog()SELECT current_schema() 的结果来完全限定标识符,并将其作为永久性关系进行查找。

如果无法将关系解析为任何表、视图或 CTE,Databricks 将引发 TABLE_OR_VIEW_NOT_FOUND 错误。

示例

-- Setting up a scenario
> USE CATALOG spark_catalog;
> USE SCHEMA default;

> CREATE TABLE rel(c1 int);
> INSERT INTO rel VALUES(1);

-- An fully qualified reference to rel:
> SELECT c1 FROM spark_catalog.default.rel;
 1

-- A partially qualified reference to rel:
> SELECT c1 FROM default.rel;
 1

-- An unqualified reference to rel:
> SELECT c1 FROM rel;
 1

-- Add a temporary view with a conflicting name:
> CREATE TEMPORARY VIEW rel(c1) AS VALUES(2);

-- For unqualified references the temporary view takes precedence over the persisted table:
> SELECT c1 FROM rel;
 2

-- Temporary views cannot be qualified, so qualifiecation resolved to the table:
> SELECT c1 FROM default.rel;
 1

-- An unqualified reference to a common table expression wins even over a temporary view:
> WITH rel(c1) AS (VALUES(3))
    SELECT * FROM rel;
 3

-- If CTEs are nested, the match nearest to the table reference takes precedence.
> WITH rel(c1) AS (VALUES(3))
    (WITH rel(c1) AS (VALUES(4))
      SELECT * FROM rel);
  4

-- To resolve the table instead of the CTE, qualify it:
> WITH rel(c1) AS (VALUES(3))
    (WITH rel(c1) AS (VALUES(4))
      SELECT * FROM default.rel);
  1

-- For a CTE to be visible it must contain the query
> SELECT * FROM (WITH cte(c1) AS (VALUES(1))
                   SELECT 1),
                cte;
  [TABLE_OR_VIEW_NOT_FOUND] The table or view `cte` cannot be found.

函数解析

函数引用由必需的尾部括号集识别。

它可以解析为:

  • Azure Databricks 提供的内置函数
  • 范围为当前会话的临时用户定义函数,或
  • 存储在 Hive 元存储或 Unity 目录中的持久性用户定义函数。

函数名称的解析取决于它是否被限定:

  • Qualified

    如果名称包含三个部分且已完全限定:catalog.schema.function,则它是唯一的。

    如果名称由两个部分组成:schema.function,则使用 SELECT current_catalog() 的结果进一步限定该名称以使其保持唯一。

    然后在目录中查找函数。

  • 未限定

    对于未限定的函数名称,Azure Databricks 遵循固定的优先顺序 (PATH):

    1. 内置函数

      如果内置函数集中存在具有此名称的函数,则选择该函数。

    2. 临时函数

      如果临时函数集中存在具有此名称的函数,则选择该函数。

    3. 永久函数

      通过在前面添加 SELECT current_catalog()SELECT current_schema() 的结果来完全限定函数名称,并将其作为永久性函数进行查找。

如果无法解析该函数,Azure Databricks 将引发 UNRESOLVED_ROUTINE 错误。

示例

> USE CATALOG spark_catalog;
> USE SCHEMA default;

-- Create a function with the same name as a builtin
> CREATE FUNCTION concat(a STRING, b STRING) RETURNS STRING
    RETURN b || a;

-- unqualified reference resolves to the builtin CONCAT
> SELECT concat('hello', 'world');
 helloworld

-- Qualified reference resolves to the persistent function
> SELECT default.concat('hello', 'world');
 worldhello

-- Create a persistent function
> CREATE FUNCTION func(a INT, b INT) RETURNS INT
    RETURN a + b;

-- The persistent function is resolved without qualifying it
> SELECT func(4, 2);
 6

-- Create a conflicting temporary function
> CREATE FUNCTION func(a INT, b INT) RETURNS INT
    RETURN a / b;

-- The temporary function takes precedent
> SELECT func(4, 2);
 2

-- To resolve the persistent function it now needs qualification
> SELECT spark_catalog.default.func(4, 3);
 6