Bootstrap

MySQL CTE 通用表表达式:基础学习

MySQL CTE 通用表表达式:基础学习

CTE(Common Table Expressions),是一个可以在单个语句范围内被创建的临时结果集,可在该语句中被多次引用。

使用基础

CTE通常以 WITH 关键字开头,后跟一个或多个子句,以逗号分隔。每个子句都提供一个结果集。

具体请看以下示例:

WITH
  cte1 AS (SELECT a, b FROM table1),
  cte2 AS (SELECT c, d FROM table2)
SELECT b, d FROM cte1 JOIN cte2
WHERE cte1.a = cte2.c;

在这个语句中,两个结果集分别被命名为cte1,cte2,并在后续的SELECT查询中使用了它们。

结果集不仅能在SELECT查询中被引用,也可以被其他CTE语句引用,从而可以使CTE能够基于其他CTE进行定义。

CTE也可以引用自身来定义递归 CTE。递归 CTE 的常见应用包括分层或树结构数据的系列生成和遍历。

CTE语法结构

CTE 是 DML 语句语法的可选部分。它们是使用 WITH 子句定义:

with_clause:
    WITH [RECURSIVE]
        cte_name [(col_name [, col_name] ...)] AS (subquery)
        [, cte_name [(col_name [, col_name] ...)] AS (subquery)] ...
  • cte_name 表示单个通用表表达式的名字,可以被当作一个临时表被引用。
  • (subquery) 部分是生成CTE结果集的子查询部分,括号是必需的。
  • 如果CTE的子查询引用其自己的名称,则该CTE表达式是递归的。那么必须包含RECURSIVE关键字。

CTE结果集临时表的列名,即 [(col_name [, col_name] ...)] 部分,遵从以下原则:

  • 如果cte_name后面是带括号的名称列表,即明确指定了列名,如下:
WITH cte (col1, col2) AS
(
  SELECT 1, 2
  UNION ALL
  SELECT 3, 4
)
SELECT col1, col2 FROM cte;

那么,子查询的结果集返回列数比如和括号中的列个数相同。

  • 否则,cte临时表的列默认来自于子查询的结果集。
WITH cte AS
(
  SELECT 1 AS col1, 2 AS col2
  UNION ALL
  SELECT 3, 4
)
SELECT col1, col2 FROM cte;

WITH 适用于哪些上下文场景?

  • SELECT, UPDATE, 以及 DELETE 等语句的开头使用:
WITH ... SELECT ...
WITH ... UPDATE ...
WITH ... DELETE ...
  • 在子查询的开头使用(包括派生表子查询):
SELECT ... WHERE id IN (WITH ... SELECT ...) ...
SELECT * FROM (WITH ... SELECT ...) AS dt ...
  • 在包含 SELECT 语句的语句中,紧接在 SELECT 之前使用:
INSERT ... WITH ... SELECT ...
REPLACE ... WITH ... SELECT ...
CREATE TABLE ... WITH ... SELECT ...
CREATE VIEW ... WITH ... SELECT ...
DECLARE CURSOR ... WITH ... SELECT ...
EXPLAIN ... WITH ... SELECT ...

同一级别只允许一个 WITH 子句。不能在同一级别后跟另一个 WITH,因此以下语句是不合法的:

WITH cte1 AS (...) WITH cte2 AS (...) SELECT ...

要使语句合法,使用一个 WITH 子句,并用逗号分隔子句:

WITH cte1 AS (...), cte2 AS (...) SELECT ...

然而,如果它们出现在不同级别,则一个语句可以包含多个 WITH 子句:

WITH cte1 AS (SELECT 1)
SELECT * FROM (WITH cte2 AS (SELECT 2) SELECT * FROM cte2 JOIN cte1) AS dt;

一个 WITH 子句可以定义一个或多个通用表表达式,但每个CTE名称必须对该子句是唯一的。以下是不合法的:

WITH cte1 AS (...), cte1 AS (...) SELECT ...

为了使语句合法,用唯一名称定义CTEs:

WITH cte1 AS (...), cte2 AS (...) SELECT ...

相互引用

一个CTE可以在其自身或者其他CTE中被引用。

  • 引用自身的CTE是递归CTE。

  • 一个CTE中被引用的其他CTE需要在其前被定义。

    该约束排除了相互递归的CTE,cte1引用cte2,cte2引用cte1。其中一个引用必须是稍后定义的CTE,这是不允许的。

  • 在给定查询块中的CTE可以引用在更外层级别的查询块中定义的CTE,但不能引用在更内层级别的查询块中定义的CTE。

对于具有相同名称的对象的引用解析,派生表隐藏CTE;而CTE隐藏基本表、临时表和视图。名称解析是通过在同一查询块中搜索对象,然后逐个到更外层块中进行,直到找到该名称的对象为止。

递归通用表表达式

请参考文章:MySQL CTEs通用表表达式:进阶学习-递归通用表表达式
https://blog.csdn.net/kaka_buka/article/details/136512460

参考链接

  • 官方文档
    https://dev.mysql.com/doc/refman/8.0/en/with.html

  • 博客文章
    https://blog.csdn.net/w13966597931/article/details/133221384
    https://blog.csdn.net/a2272062968/article/details/131888595

;