流运算符

流运算符将 SQL 语句链接在一起,其中一个语句的结果用作另一个语句的输入。目前,管道运算符 (->>) 是 Snowflake 支持的唯一流运算符。

管道

管道运算符与命令行上的 Unix 管道 (|) 类似,但用于 SQL 语句而不是 Unix 命令。要使用管道运算符,请指定一系列由该运算符分隔的 SQL 语句。您可以指定任何有效的 SQL 语句,例如 SHOW、SELECT、CREATE、INSERT 等。在第一个 SQL 语句之后,每个后续语句都可以将任何先前语句的结果作为输入。在 FROM 子句中,先前的 SQL 语句由带有美元符号 ($) 和管道号的参数引用,管道号是该语句在链中的相对位置,从当前语句开始倒数。

管道运算符将以下一系列 SQL 语句链接在一起,注释显示每个语句的相对引用编号:

first_st -- Referenced as $4 in last_st, $3 in fourth_st, $2 in third_st, and $1 in second_st
  ->> second_st -- Referenced as $3 in last_st, $2 in fourth_st, and $1 in third_st
  ->> third_st  -- Referenced as $2 in last_st and $1 in fourth_st
  ->> fourth_st -- Referenced as $1 in last_st
  ->> last_st;
Copy

例如,这一系列 SQL 语句在三个 SELECT 语句中都有管道号引用,并且每个语句都将第一个 SELECT 语句的结果作为输入:

SELECT ...
  ->> SELECT ... FROM $1
  ->> SELECT ... FROM $2
  ->> SELECT ... FROM $3;
Copy

如图所示,通过在最后一个 SQL 语句后面加上分号来结束语句链。不要在链中前面的语句后面加分号。整个链的输出是最后一个 SQL 语句的最终结果。客户工具(例如 SnowSQL)将语句链视为单个语句。

管道运算符具有以下优势:

  • 简化依赖 SQL 语句的执行。

  • 提高复杂 SQL 运算的可读性和灵活性。

语法

<sql_statement_1> ->> <sql_statement_2> [ ->> <sql_statement_n> ... ]
Copy

使用说明

  • 每个语句产生的结果只能由链中的后续语句使用。

  • 语句按其指定顺序执行。与 RESULT_SCAN(LAST_QUERY_ID()) 不同的是,无论其他查询是否在链外同时运行,管道号都会解析为链中正确的结果集。

  • 当一个语句使用前一个语句的结果时,所使用的结果集等同于通过 RESULT_SCAN 函数并传入前一个语句的查询 ID 所返回的结果集。

    例如,以下语句将 SHOW WAREHOUSES 命令的输出限制为特定列:

    SHOW WAREHOUSES;
    
    SELECT "name", "state", "type", "size"
      FROM TABLE(RESULT_SCAN(LAST_QUERY_ID(-1)));
    
    Copy

    此语句使用管道运算符生成相同的结果:

    SHOW WAREHOUSES
      ->> SELECT "name", "state", "type", "size" FROM $1;
    
    Copy
  • 不能保证使用管道运算符的查询返回行的顺序与链中前一个查询的输入结果集的顺序相同。您可以在查询中包含 ORDER BY 子句,以指定顺序。

  • 任何 SQL 语句引发的错误都会停止链的执行,并将该错误返回给客户端。

  • 最后一个语句的结果将返回给客户端。

  • 这些语句作为 :doc:` Snowflake Scripting </developer-guide/snowflake-scripting/index>` 匿名块执行。

限制

  • $n 参数仅在 SQL 语句的 FROM 子句中有效。

  • 每个 SQL 语句产生的结果只能由管道链中的后续语句使用。结果不能在管道链之外使用,最后一个语句的结果除外。

  • 不支持位置绑定变量。

示例

以下示例使用管道运算符:

为 SHOW 命令的输出选择列的列表

运行 SHOW TABLES 命令,使用管道运算符将输出限制为 2025 年 4 月 15 日之后创建的表的 created_onnameowner 列。

SHOW TABLES
  ->> SELECT "created_on" AS creation_date,
             "name" AS table_name,
             "owner" AS table_owner
        FROM $1
        WHERE creation_date > '2025-04-15'::DATE;
Copy
+-------------------------------+-------------+--------------+
| CREATION_DATE                 | TABLE_NAME  | TABLE_OWNER  |
|-------------------------------+-------------+--------------|
| 2025-04-16 08:46:16.130 -0700 | TEST_TABLE1 | ACCOUNTADMIN |
| 2025-04-16 09:44:13.701 -0700 | MYTABLE1    | USER_ROLE    |
| 2025-04-16 08:46:32.092 -0700 | MYTABLE2    | USER_ROLE    |
+-------------------------------+-------------+--------------+

执行从多个表的查询中获取输入的查询

首先,创建一个 dept_pipe_demo 表和一个 emp_pipe_demo 表,并在每个表中插入数据:

CREATE OR REPLACE TABLE dept_pipe_demo (
  deptno NUMBER(2),
  dname VARCHAR(14),
  loc VARCHAR(13)
  ) AS SELECT * FROM VALUES
     (10, 'ACCOUNTING', 'NEW YORK'),
     (20, 'RESEARCH', 'DALLAS'),
     (30, 'SALES', 'CHICAGO'),
     (40, 'OPERATIONS', 'BOSTON');

CREATE OR REPLACE TABLE emp_pipe_demo (
  empno NUMBER(4),
  ename VARCHAR(10),
  sal NUMBER(7,2),
  deptno NUMBER(2)
  ) AS SELECT * FROM VALUES
    (7369, 'SMITH', 800, 20),
    (7499, 'ALLEN', 1600, 30),
    (7521, 'WARD', 1250, 30),
    (7698, 'BLAKE', 2850, 30),
    (7782, 'CLARK', 2450, 10);
Copy

以下示例将管道运算符用于执行以下运算的 SQL 语句链:

  1. 查询 dept_pipe_demo 表以返回 dname 等于 SALES 的行。

  2. 通过在 FROM 子句的 WHERE 条件中指定 $1,使用先前查询的结果作为输入,在 emp_pipe_demo 表中查询 SALES 部门中工资高于 1500 的员工。

  3. 通过在 FROM 子句中指定 $1,使用先前查询的结果作为输入,运行返回 enamesal 值的查询。

SELECT * FROM dept_pipe_demo WHERE dname = 'SALES'
  ->> SELECT * FROM emp_pipe_demo WHERE sal > 1500 AND deptno IN (SELECT deptno FROM $1)
  ->> SELECT ename, sal FROM $1 ORDER BY 2 DESC;
Copy
+-------+---------+
| ENAME |     SAL |
|-------+---------|
| BLAKE | 2850.00 |
| ALLEN | 1600.00 |
+-------+---------+

备注

此示例的目的是展示如何将一系列查询与管道运算符结合使用。但是,使用联接查询可以实现相同的输出,并且联接查询的性能通常比结合使用管道运算符的查询更好。

返回事务中 DML 运算的行数

创建表并逐一插入行。链接所有语句允许您使用管道运算符来检查每个 INSERT 语句的结果,这表示插入的总行数。

在示例中的每个 SELECT 语句中,SELECT 列表中的 $1 都是第一列的速记引用,而不是管道中先前的结果。管道号的 $n 参数仅在 FROM 子句中有效。

CREATE OR REPLACE TABLE test_sql_pipe_dml (a INT, b INT)
  ->> INSERT INTO test_sql_pipe_dml VALUES (1, 2)
  ->> INSERT INTO test_sql_pipe_dml VALUES (3, 4)
  ->> INSERT INTO test_sql_pipe_dml VALUES (5, 6)
  ->> INSERT INTO test_sql_pipe_dml VALUES (7, 8)
  ->> SELECT (SELECT $1 FROM $4) +
             (SELECT $1 FROM $3) +
             (SELECT $1 FROM $2) +
             (SELECT $1 FROM $1)
        AS "Number of rows";
Copy
+----------------+
| Number of rows |
|----------------|
|              4 |
+----------------+

以下示例将管道运算符用于执行以下运算的 SQL 语句链:

  1. 开始一个事务。

  2. 在先前创建的表中插入一行。

  3. 从表中删除行。

  4. 更新表中的行。

  5. 提交事务。

  6. 查询受每项 DML 运算影响的行数。

EXECUTE IMMEDIATE $$
BEGIN TRANSACTION
  ->> INSERT INTO test_sql_pipe_dml VALUES (1, 2)
  ->> DELETE FROM test_sql_pipe_dml WHERE a = 1
  ->> UPDATE test_sql_pipe_dml SET b = 2
  ->> COMMIT
  ->> SELECT
        (SELECT $1 FROM $4) AS "Inserted rows",
        (SELECT $1 FROM $3) AS "Deleted rows",
        (SELECT $1 FROM $2) AS "Updated rows";
$$;
Copy
+---------------+--------------+--------------+
| Inserted rows | Deleted rows | Updated rows |
|---------------+--------------+--------------|
|             1 |            2 |            3 |
+---------------+--------------+--------------+

返回稍后删除的表中插入的结果

此示例将管道运算符用于执行以下运算的 SQL 语句链:

  1. 创建带有 IDENTITY 列的表。

  2. 将行插入表中。

  3. 查询表。

  4. 删除表。

  5. 查询管道号 ``$2``(SELECT 语句)的结果。

最后一个 SELECT 语句所使用的结果集等同于通过 RESULT_SCAN 函数为前一 SELECT 语句的查询 ID 返回的结果集。

CREATE OR REPLACE TABLE test_sql_pipe_drop (
    id INT IDENTITY START 10 INCREMENT 1,
    data VARCHAR)
  ->> INSERT INTO test_sql_pipe_drop (data) VALUES ('row1'), ('row2'), ('row3')
  ->> SELECT * FROM test_sql_pipe_drop
  ->> DROP TABLE test_sql_pipe_drop
  ->> SELECT COUNT(*) "Number of rows", MAX(id) AS "Last ID" FROM $2;
Copy
+----------------+---------+
| Number of rows | Last ID |
|----------------+---------|
|              3 |      12 |
+----------------+---------+
语言: 中文