某次见一个商分同学写的 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
语法
WITH <cte_name> [ ( column_name [ , ... ] ) ]
AS
( cte_query )
[ , < another_cte_expression > ]
<query>
说明(没实操过,只是查资料,所以可能不准确):
- 一个
WITH
可以 包含多个 CTE 表达式,用逗号连接;好像是不能同时写多个。 - 必须在
WITH
后紧接着的一条查询中使用该 CTE 表达式,否则 CTE 将失效(紧跟着 n 个查询,只有第一个能用,剩下 n-1 个不可用)。 - 在一个查询中,已声明的 CTE 表达式可以使用多次。
说明 2 + 3 有一些没解释明白的地方,例如一次声明 CTE1 和 CTE2 后,可以 SELECT FROM CTE1 UNION ALL SELECT FROM CTE2。那么这是算作一次查询呢?还是算作 CTE2 没有在第一次查询中使用,是可以被第二个查询使用的呢?我没找到对此做出说明的资料,需要有机会做实验。 - 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
参考
- https://help.aliyun.com/document_detail/98769.html
- https://docs.microsoft.com/en-us/sql/t-sql/queries/with-common-table-expression-transact-sql?view=sql-server-ver15
- https://www.geeksforgeeks.org/cte-in-sql/
- https://www.databasestar.com/sql-cte-with/
- https://www.cnblogs.com/Neo-ds/p/4804900.html
- https://www.cnblogs.com/zhangweizhong/archive/2015/10/29/4921869.html
- https://bbs.csdn.net/topics/390743921
- https://stackoverflow.com/questions/11542288/how-do-you-union-with-multiple-ctes
- https://blog.csdn.net/weixin_41600552/article/details/82958942