某次见一个商分同学写的 SQL 里用到了 WITH 语句,来学习一下。

概述

使用 CTE(Common Table Expression)来声明在一定范围内可被灵活复用的子查询,相比建临时表或者嵌套子查询的方法,更便于阅读、维护以及实现进阶效果。

有两份释义:

Specifies a temporary named result set, known as a common table expression (CTE). — Microsoft

The Common Table Expressions (CTE) were introduced into standard SQL in order to simplify various classes of SQL Queries for which a derived table was just unsuitable. — GeeksForGeeks

语法

  1. WITH <cte_name> [ ( column_name [ , ... ] ) ]
  2. AS
  3. ( cte_query )
  4. [ , < another_cte_expression > ]
  5. <query>

说明(没实操过,只是查资料,所以可能不准确):

  1. 一个WITH可以 包含多个 CTE 表达式,用逗号连接;好像是不能同时写多个。
  2. 必须在WITH后紧接着的一条查询中使用该 CTE 表达式,否则 CTE 将失效(紧跟着 n 个查询,只有第一个能用,剩下 n-1 个不可用)。
  3. 在一个查询中,已声明的 CTE 表达式可以使用多次。
    说明 2 + 3 有一些没解释明白的地方,例如一次声明 CTE1 和 CTE2 后,可以 SELECT FROM CTE1 UNION ALL SELECT FROM CTE2。那么这是算作一次查询呢?还是算作 CTE2 没有在第一次查询中使用,是可以被第二个查询使用的呢?我没找到对此做出说明的资料,需要有机会做实验。
  4. CTE 可以嵌套上文已经声明的 CTE,也可以嵌套自己构成递归查询。
    // 不得不说,很多技术博客对“forward reference is not allowed”的翻译真是差劲,非常容易让人不理解到底是上文还是下文。这与正则表达式正向、反向查询如出一辙。

举个例子:

WITH CTE_1
    AS
    (
        SELECT * FROM Person
    ),
    CTE_2
    AS
    (
        SELECT * FROM CTE_1
    )
SELECT * FROM CTE_1
UNION
SELECT * FROM CTE_2

参考