EXECUTE IMMEDIATE FROM

EXECUTE IMMEDIATE FROM 在暂存区执行文件中指定的 SQL 语句。该文件可以包含 SQL 语句或 Snowflake Scripting 块。这些语句必须是语法正确的 SQL 语句。

可以使用 EXECUTE IMMEDIATE FROM 命令从任何 Snowflake 会话中执行文件中的语句。

此功能提供了一种机制,可控制 Snowflake 对象和代码的部署和管理。例如,可以执行存储脚本,为所有账户创建标准的 Snowflake 环境。配置脚本可以包含为每个新账户创建用户、角色、数据库和架构的语句。

Jinja2 模板化

EXECUTE IMMEDIATE FROM 也可以使用 Jinja2 模板化语言执行模板文件。模板可以包含变量和表达式,允许使用循环、条件、变量替换、宏等。

要执行的模板文件必须是:

  • 语法有效的 Jinja2 模板。

  • 位于暂存区或 Git 存储库 中。

  • 能够呈现语法正确的 SQL 语句。

模板化可实现更灵活的控制结构和使用环境变量的参数化。例如,您可以使用模板动态选择脚本中定义的对象的部署目标。要使用模板呈现 SQL 脚本,请使用 模板化指令 或添加具有至少一个模板变量的 USING 子句

模板化指令

您可以使用两个模板化指令中的任何一个。

推荐的指令使用有效的 SQL 语法:

--!jinja
Copy

或者,您可以使用替代指令:

#!jinja
Copy

备注

指令前面只能放置一个字节顺序标记和最多 10 个空白字符(换行符、制表符、空格)。在同一行的指令之后的任何字符都将被忽略。

另请参阅:

EXECUTE IMMEDIATE

语法

EXECUTE IMMEDIATE
  FROM { absoluteFilePath | relativeFilePath }
  [ USING ( <key> => <value> [ , <key> => <value> [ , ... ] ]  )  ]
Copy

其中:

absoluteFilePath ::=
   @[ <namespace>. ]<stage_name>/<path>/<filename>
Copy
relativeFilePath ::=
  '[ / | ./ | ../ ]<path>/<filename>'
Copy

必填参数

绝对文件路径 (absoluteFilePath)

namespace

内部或外部暂存区所在的数据库和/或架构,形式为 database_name.schema_nameschema_name。如果数据库和架构当前正在用户会话中使用,则命名空间为 可选;否则,为必需。

stage_name

内部或外部暂存区的名称。

path

暂存区中文件的路径(区分大小写)。

filename

要执行的文件的名称。它必须包含语法正确且有效的 SQL 语句。每个语句必须用分号分隔。

相对文件路径 (relativeFilePath)

path

暂存区中文件的相对路径(区分大小写)。相对路径支持既定的约定,如前导 / 指示暂存区文件系统的根,./ 引用当前目录(父文件所在的目录),../ 引用父目录。有关更多信息,请参阅 使用说明

filename

要执行的文件的名称。它必须包含语法正确且有效的 SQL 语句。每个语句必须用分号分隔。

可选参数

USING ( <key> => <value> [ , <key> => <value> [ , ... ] ]  )

允许您传递一个或多个可用于参数化模板扩展的键值对。键值对必须形成逗号分隔的列表。

当存在 USING 子句时,文件首先 呈现为 Jinja2 模板,然后作为 SQL 脚本执行。

其中:

  • key 是模板变量的名称。模板变量名称可以选择放在双引号 (") 内。

  • value 是模板中要分配给变量的值。字符串值必须放在 '$$ 内。有关示例,请参阅 模板化使用说明

返回

EXECUTE IMMEDIATE FROM 返回:

  • 文件中最后一个语句的结果(如果所有语句都已成功执行)。

  • 错误消息(如果文件中的任何语句失败)。

    如果文件中的任何语句存在错误,则 EXECUTE IMMEDIATE FROM 命令将失败,并返回失败语句的错误消息。

    备注

    如果 EXECUTE IMMEDIATE FROM 命令失败并返回错误消息,则文件中位于失败语句之前的任何语句都已成功完成。

访问控制要求

  • 用于执行 EXECUTE IMMEDIATE FROM 命令的 角色 必须对文件所在的暂存区具有 USAGE(外部暂存区)或 READ(内部暂存区)权限。

  • 用于执行文件的角色只能执行其具有权限的文件中的语句。例如,如果文件中存在 CREATE TABLE 语句,则角色必须具有在账户中 创建表所需的权限,否则该语句将失败。

请注意,对架构中的对象进行操作还需要对父数据库和架构具有 USAGE 权限。

有关创建具有指定权限集的自定义角色的说明,请参阅 创建自定义角色

有关对 安全对象 执行 SQL 操作的相应角色和权限授予的一般信息,请参阅 访问控制概述

使用说明

  • 要执行的文件中的 SQL 语句可以包含 EXECUTE IMMEDIATE FROM 语句:

    • 嵌套的 EXECUTE IMMEDIATE FROM 语句 可以 使用 相对文件路径

      相对路径是相对于父文件的暂存区和文件路径进行评估的。如果相对文件路径以 / 开头,则该路径从包含父文件的暂存区的根目录开始。

      有关示例,请参阅 示例

    • 相对文件路径必须放在单引号 (') 或 $$ 内。

    • 嵌套文件的最大执行深度为 5。

  • 绝对文件路径可以选择放在单引号 (') 或 $$ 内。

  • 要执行的文件不能大于 10MB。

  • 要执行的文件必须采用 UTF-8 (link removed) 编码。

  • 要执行的文件必须解压缩。如果使用 PUT 命令将文件上传到内部暂存区,则必须将 AUTO_COMPRESS 参数 显式设置为 FALSE。

    例如,将 my_file.sql 上传到 my_stage

    PUT file://~/sql/scripts/my_file.sql @my_stage/scripts/
      AUTO_COMPRESS=FALSE;
    
    Copy
  • 不支持执行目录中的所有文件。例如,EXECUTE IMMEDIATE FROM @stage_name/scripts/ 导致错误。

模板化使用说明

  • 模板中的变量名称区分大小写。

  • 模板变量名可以选择放在双引号内。如果将任何 保留的关键字 用作变量名称,则将变量名称放在引号内。

  • USING 子句中支持以下参数类型:

    • 字符串。必须放在 '$$ 内。例如 USING (a => 'a', b => $$b$$)

    • 数字(十进制和整型)。例如 USING (a => 1, b => -1.23)

    • 布尔。例如 USING (a => TRUE, b => FALSE)

    • NULL。例如 USING (a => NULL)

      备注

      Jinja2 模板化引擎将 NULL 值解释为 Python NoneType 类型。

    • 会话变量。例如 USING (a => $var)。只允许包含支持的数据类型值的会话变量。

    • 绑定变量。例如 USING (a => :var)。只允许绑定包含支持的数据类型值的变量。您可以使用绑定变量将存储过程实参传递给模板。

  • 目前模板呈现的最大结果大小为 90 KB。

  • 模板使用 Jinja2 3.1.2 模板化引擎呈现。

EXECUTE IMMEDIATE FROM 错误故障排除

本节包含由 EXECUTE IMMEDIATE FROM 语句导致的一些常见错误以及如何解决这些错误。

文件错误

错误

001501 (02000): File '<directory_name>' not found in stage '<stage_name>'.

原因

此错误有多种原因:

  • 文件不存在。

  • 文件名是一个目录的根。例如 @stage_name/scripts/

解决方案

验证文件的名称并确认文件存在。不支持执行目录中的所有文件。

错误

001503 (42601): Relative file references like '<filename.sql>' cannot be used in top-level EXECUTE IMMEDIATE calls.

原因

语句是使用文件执行之外的相对文件路径执行的。

解决方案

相对文件路径只能在文件中的 EXECUTE IMMEDIATE FROM 语句中使用。使用文件的 绝对文件路径。有关更多信息,请参阅 使用说明

错误

001003 (42000): SQL compilation error: syntax error line <n> at position <m> unexpected '<string>'.

原因

该文件包含 SQL 语法错误。

解决方案

修复文件中的语法错误,并将文件重新上传到暂存区。

暂存区错误

错误

002003 (02000): SQL compilation error: Stage '<stage_name>' does not exist or not authorized.

原因

该暂存区不存在或您无权访问该暂存区。

解决方案

  • 验证暂存区的名称并确认暂存区存在。

  • 使用具有访问暂存区所需权限的角色执行语句。有关更多信息,请参阅 访问控制要求

访问控制错误

错误

003001 (42501): Uncaught exception of type 'STATEMENT_ERROR' in file <file_name> on line <n> at position <m>:
SQL access control error: Insufficient privileges to operate on schema '<schema_name>'

原因

用于执行语句的角色不具有执行文件中部分或全部语句所需的权限。

解决方案

使用具有相应权限的角色来执行文件中的语句。有关更多信息,请参阅 访问控制要求

另请参阅:暂存区错误

模板化错误

错误

001003 (42000): SQL compilation error:
syntax error line [n] at position [m] unexpected '{'.

原因

该文件包含模板化构造(例如,{{ table_name }}),但未使用模板化引擎呈现。如果未呈现模板,模板中的文本行将作为 SQL 语句执行。文件中的模板化构造可能会导致 SQL 语法错误。

解决方案

添加一个 模板化指令,或者使用 USING 子句 重新执行语句,并指定至少一个模板变量。

错误

000005 (XX000): Python Interpreter Error:
jinja2.exceptions.UndefinedError: '<key>' is undefined
in template processing

原因

如果在 USING 子句中未指定模板中使用的任何变量,则会发生错误。

解决方案

验证模板中变量的名称和数量,并更新 USING 子句以包括所有模板变量的值。

错误

001510 (42601): Unable to use value of template variable '<key>'

原因

变量 key 的值是不受支持的类型。

解决方案

验证您正在使用模板变量值支持的参数类型。有关更多信息,请参阅 模板化使用说明

示例

基本示例

此示例执行位于 my_stage 暂存区中的 create-inventory.sql 文件。

  1. 创建名为 create-inventory.sql 且包含以下语句的文件:

    CREATE OR REPLACE TABLE my_inventory(
      sku VARCHAR,
      price NUMBER
    );
    
    EXECUTE IMMEDIATE FROM './insert-inventory.sql';
    
    SELECT sku, price
      FROM my_inventory
      ORDER BY price DESC;
    
    Copy
  2. 创建名为 insert-inventory.sql 且包含以下语句的文件:

    INSERT INTO my_inventory
      VALUES ('XYZ12345', 10.00),
             ('XYZ81974', 50.00),
             ('XYZ34985', 30.00),
             ('XYZ15324', 15.00);
    
    Copy
  3. 创建内部暂存区 my_stage

    CREATE STAGE my_stage;
    
    Copy
  4. 使用 PUT 命令将这两个本地文件上传到该暂存区:

    PUT file://~/sql/scripts/create-inventory.sql @my_stage/scripts/
      AUTO_COMPRESS=FALSE;
    
    PUT file://~/sql/scripts/insert-inventory.sql @my_stage/scripts/
      AUTO_COMPRESS=FALSE;
    
    Copy
  5. 执行位于 my_stage 中的 create-inventory.sql 脚本:

    EXECUTE IMMEDIATE FROM @my_stage/scripts/create-inventory.sql;
    
    Copy

    返回:

    +----------+-------+
    | SKU      | PRICE |
    |----------+-------|
    | XYZ81974 |    50 |
    | XYZ34985 |    30 |
    | XYZ15324 |    15 |
    | XYZ12345 |    10 |
    +----------+-------+
    

一个简单的模板示例

  1. 创建包含两个变量和模板化指令的模板文件 setup.sql

    --!jinja
    
    CREATE SCHEMA {{env}};
    
    CREATE TABLE RAW (COL OBJECT)
        DATA_RETENTION_TIME_IN_DAYS = {{retention_time}};
    
    Copy
  2. 创建一个暂存区 – 如果您已经有一个可以上传文件的暂存区,则为 可选

    例如,在 Snowflake 中创建内部暂存区:

    CREATE STAGE my_stage;
    
    Copy
  3. 将文件上传到暂存区。

    例如,使用本地环境中的 PUT 命令将文件 setup.sql 上传到暂存区 my_stage

    PUT file://path/to/setup.sql @my_stage/scripts/
      AUTO_COMPRESS=FALSE;
    
    Copy
  4. 执行文件 setup.sql

    EXECUTE IMMEDIATE FROM @my_stage/scripts/setup.sql
        USING (env=>'dev', retention_time=>0);
    
    Copy

带有条件和循环的模板示例

  1. 创建模板文件并包括模板化指令。

    例如,在本地环境中创建文件 setup-env.sql

    --!jinja2
    
    {% if DEPLOYMENT_TYPE == 'prod' %}
      {% set environments = ['prod1', 'prod2'] %}
    {% else %}
      {% set environments = ['dev', 'qa', 'staging'] %}
    {% endif %}
    
    {% for environment in environments %}
      CREATE DATABASE {{ environment }}_db;
      USE DATABASE {{ environment }}_db;
      CREATE TABLE {{ environment }}_orders (
        id NUMBER,
        item VARCHAR,
        quantity NUMBER);
      CREATE TABLE {{ environment }}_customers (
        id NUMBER,
        name VARCHAR);
    {% endfor %}
    
    Copy
  2. 创建一个暂存区 – 如果您已经有一个可以上传文件的暂存区,则为 可选

    例如,在 Snowflake 中创建内部暂存区:

    CREATE STAGE my_stage;
    
    Copy
  3. 将文件上传到暂存区。

    例如,使用本地环境中的 PUT 命令将文件 setup-env.sql 上传到暂存区 my_stage

    PUT file://path/to/setup-env.sql @my_stage/scripts/
      AUTO_COMPRESS=FALSE;
    
    Copy
  4. 执行文件 setup-env.sql

    EXECUTE IMMEDIATE FROM @my_stage/scripts/setup-env.sql
      USING (DEPLOYMENT_TYPE => 'staging');
    
    Copy
语言: 中文