查询中的名称解析
在查询中,不合格的对象名称通过搜索路径进行解析。
搜索路径通常包含当前架构,但也可包含其他架构。
搜索路径存储在会话级参数 SEARCH_PATH 中。与任何其他参数类似,可使用 ALTER SESSION 命令更改此参数。
搜索路径的值是使用逗号分隔的标识符列表。该列表可以包含完全限定或部分限定的架构名称。每个架构名称都可以是 加双引号的标识符。
搜索路径还可以包含以下伪变量:
- $current
指定当前架构(请参见上文)。
- $public
指定当前数据库的公共架构。公共架构的名称由 Snowflake 维护的内部属性确定,该属性通常设置为 PUBLIC (针对为每个数据库自动创建的 PUBLIC 架构)。
这些伪变量的名称不区分大小写。
搜索路径的默认值为 $current, $public。
如果用户为搜索路径指定了新值,则验证新值。新值中指定的每个架构标识符都必须对应于一个现有架构。(具体而言,每个非限定架构都必须对应于当前数据库中的一个现有架构)。否则将引发错误,search_path 将保留其先前的值。但伪变量可以自由使用。例如,即使当前数据库没有公共架构,也可使用 $public。
每次使用 SEARCH_PATH 参数时,系统都会重新解析该参数的值。因此,更改当前架构会更改 $current 的含义,更改当前数据库会更改 $public 的含义以及任何非限定模式的含义。
如果删除了搜索路径中的架构,或更改了当前数据库,并且新数据库中不存在搜索路径中的某些非限定架构,则不会引发错误。
SEARCH_PATH 未在 视图 或 UDFs 内使用。视图或 UDF 定义中的所有不合格的对象均 仅 在视图或 UDF 的架构中解析。
可以通过 SHOW PARAMETERS 命令来检查搜索路径的字面量值。
若要查看将为查询中的不合格的对象搜索的架构,请使用 CURRENT_SCHEMAS 函数。该函数的返回值会包含搜索路径中的一系列完全限定架构,架构之间使用逗号分隔。
例如:
SELECT CURRENT_SCHEMAS();
+-------------------+
| CURRENT_SCHEMAS() |
+-------------------+
| [] |
+-------------------+
USE DATABASE mytestdb;
SELECT current_schemas();
+---------------------+
| CURRENT_SCHEMAS() |
+---------------------+
| ["MYTESTDB.PUBLIC"] |
+---------------------+
CREATE SCHEMA private;
SELECT current_schemas();
+-----------------------------------------+
| CURRENT_SCHEMAS() |
+-----------------------------------------+
| ["MYTESTDB.PRIVATE", "MYTESTDB.PUBLIC"] |
+-----------------------------------------+
伪变量将扩展到其当前值,非限定架构将变为完全限定形式,而不存在或不可见的架构将被忽略。
SHOW PARAMETERS LIKE 'search_path';
+-------------+--------------------+--------------------+------------------------------------------------+
| key | value | default | description |
+-------------+--------------------+--------------------+------------------------------------------------+
| SEARCH_PATH | $current, $public, | $current, $public, | Search path for unqualified object references. |
+-------------+--------------------+--------------------+------------------------------------------------+
SELECT current_schemas();
+---------------------------------------------------------------------------+
| CURRENT_SCHEMAS() |
+---------------------------------------------------------------------------+
| [XY12345.TESTDB.TESTSCHEMA, XY12345.TESTDB.PUBLIC, SAMPLES.COMMON.PUBLIC] |
+---------------------------------------------------------------------------+
+------------------------------------+
| status |
+------------------------------------+
| Database DB1 successfully created. |
+------------------------------------+
+----------------------------------+
| status |
+----------------------------------+
| Statement executed successfully. |
+----------------------------------+
SELECT current_schemas();
+---------------------------------------------+
| CURRENT_SCHEMAS() |
+---------------------------------------------+
| [XY12345.DB1.PUBLIC, SAMPLES.COMMON.PUBLIC] |
+---------------------------------------------+
ALTER SESSION SET search_path='$current, $public, testdb.public';
+----------------------------------+
| status |
+----------------------------------+
| Statement executed successfully. |
+----------------------------------+
SHOW PARAMETERS LIKE 'search_path';
+-------------+----------------------------------+--------------------+------------------------------------------------+
| key | value | default | description |
+-------------+----------------------------------+--------------------+------------------------------------------------+
| SEARCH_PATH | $current, $public, testdb.public | $current, $public, | Search path for unqualified object references. |
+-------------+----------------------------------+--------------------+------------------------------------------------+
SELECT current_schemas();
+---------------------------------------------+
| CURRENT_SCHEMAS() |
+---------------------------------------------+
| [XY12345.DB1.PUBLIC, XY12345.TESTDB.PUBLIC] |
+---------------------------------------------+
当列名与别名冲突时的优先级
您可以创建包含与列名相同的别名的查询(但通常不建议这样做):
SELECT x, some_expression AS x
FROM ...
如果子句中包含的名称同时匹配列名和别名,则该子句将使用列名。以下示例通过 GROUP BY 子句演示了此行为:
创建表并插入行:
CREATE TABLE employees (salary FLOAT, state VARCHAR, employment_state VARCHAR);
INSERT INTO employees (salary, state, employment_state) VALUES
(60000, 'California', 'Active'),
(70000, 'California', 'On leave'),
(80000, 'Oregon', 'Active');
以下查询返回在职员工的薪资总和以及休假员工的薪资总和:
SELECT SUM(salary), ANY_VALUE(employment_state)
FROM employees
GROUP BY employment_state;
+-------------+-----------------------------+
| SUM(SALARY) | ANY_VALUE(EMPLOYMENT_STATE) |
|-------------+-----------------------------|
| 140000 | Active |
| 70000 | On leave |
+-------------+-----------------------------+
接下来的查询使用了别名 state,该别名与查询表中的某一列名相同。在 GROUP BY 子句中使用 state 时,Snowflake 会将其解释为对列名的引用,而非别名。因此,此查询返回的是加利福尼亚州和俄勒冈州员工的薪资总和,但显示的却是 employment_state 信息(例如 Active),而不是具体的州或省份名称:
SELECT SUM(salary), ANY_VALUE(employment_state) AS state
FROM employees
GROUP BY state;
+-------------+--------+
| SUM(SALARY) | STATE |
|-------------+--------|
| 130000 | Active |
| 80000 | Active |
+-------------+--------+