名称解析
适用于: Databricks SQL Databricks Runtime
名称解析是将标识符解析为特定列、字段、参数或表引用的过程。
列、字段、参数和变量解析
表达式中的标识符可以是对以下任一项的引用:
- 基于视图、表、通用表表达式 (CTE) 的列名称,或者 column_alias。
- 结构或映射中的字段名称或映射键。 永远不会取消限定字段和键。
- SQL 用户定义的函数的参数名称。
- 变量名称。
- 一个不需要使用
()
的特殊函数,例如current_user
或current_date
。 - 在
INSERT
、UPDATE
、MERGE
或SET VARIABLE
的上下文中用于将列或变量值设置为其默认值的DEFAULT
关键字。
名称解析应用以下原则:
- 最接近的匹配引用优先,并且
- 列和参数优先于字段和键。
具体而言,标识符到特定引用的解析按顺序遵循以下规则:
局部引用
列引用
将可能已限定的标识符与
FROM clause
的表引用中的列名称进行匹配。如果存在多个此类匹配项,则引发 AMBIGUOUS_COLUMN_OR_FIELD 错误。
无参数函数引用
如果标识符未限定并且与
current_user
、current_date
或current_timestamp
匹配:则将其解析为以下函数之一。列默认规范
如果标识符未限定、与
default
匹配并且在UPDATE SET
、INSERT VALUES
或MERGE WHEN [NOT] MATCHED
的上下文中构成了完整表达式:则解析为INSERT
、UPDATE
或MERGE
的目标表的相应DEFAULT
值。结构字段或映射键引用
如果标识符已限定,则根据以下步骤尝试将它与字段或映射键进行匹配:
A. 删除最后一个标识符,并将其视为字段或键。 B. 将余下部分与
FROM clause
的表引用中的列进行匹配。如果存在多个此类匹配项,则引发 AMBIGUOUS_COLUMN_OR_FIELD 错误。
如果存在匹配项并且列为:
STRUCT
:匹配字段。如果无法匹配字段,则引发 FIELD_NOT_FOUND 错误。
如果存在多个字段,则引发 AMBIGUOUS_COLUMN_OR_FIELD 错误。
MAP
:如果键已限定,则引发错误。如果映射中实际不存在该键,则可能会出现运行时错误。
任何其他类型:引发错误。 C. 重复上述步骤以删除作为字段的尾部标识符。 应用规则 (A) 和 (B),同时保留一个解释为列的标识符。
横向列别名
适用于: Databricks SQL Databricks Runtime 12.2 LTS 及更高版本
如果表达式位于
SELECT
列表中,则将前导标识符与该SELECT
列表中的上一列别名进行匹配。如果存在多个此类匹配项,则引发 AMBIGUOUS_LATERAL_COLUMN_ALIAS 错误。
将余下的每个标识符作为字段或映射键进行匹配,如果无法匹配,则引发 FIELD_NOT_FOUND 或 AMBIGUOUS_COLUMN_OR_FIELD 错误。
相关性
LATERAL
如果查询的前面带有
LATERAL
关键字,则应用规则 1.a 和 1.d,同时考虑FROM
中包含该查询和LATERAL
前面部分的表引用。常规
如果查询是标量子查询、
IN
或EXISTS
子查询,则应用规则 1.a、1.d 和 2,同时考虑包含查询的FROM
子句中的表引用。
嵌套关联
重新应用规则 3 并迭代查询的嵌套级别。
例程参数
如果表达式是 CREATE FUNCTION 语句的一部分:
- 将标识符与参数名称进行匹配。 如果标识符已限定,则限定符必须与函数的名称匹配。
- 如果标识符已限定,则遵循规则 1.c 与参数的字段或映射键进行匹配
变量
- 将标识符与变量名称匹配。 如果标识符已限定,则限定符必须是
session
或system.session
。 - 如果标识符已限定,则遵循规则 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()
的结果进一步限定该标识符以使其保持唯一。未限定
通用表表达式
如果引用在
WITH
子句的范围内,则将标识符与某个 CTE 进行匹配,该 CTE 从直接包含的WITH
子句开始,并从该子句外移。临时视图
将标识符与当前会话中定义的任何临时视图进行匹配。
永久性表
通过在前面添加
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.
函数解析
函数引用由必需的尾部括号集识别。
它可以解析为:
函数名称的解析取决于它是否被限定:
Qualified
如果名称包含三个部分且已完全限定:
catalog.schema.function
,则它是唯一的。如果名称由两个部分组成:
schema.function
,则使用SELECT current_catalog()
的结果进一步限定该名称以使其保持唯一。然后在目录中查找函数。
未限定
对于未限定的函数名称,Azure Databricks 遵循固定的优先顺序 (
PATH
):内置函数
如果内置函数集中存在具有此名称的函数,则选择该函数。
临时函数
如果临时函数集中存在具有此名称的函数,则选择该函数。
永久函数
通过在前面添加
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