MySQL的SQL语句 - 数据操做语句(17)- WITH 语句(1)

WITH(公共表表达式)html

公共表表达式(common table expression,CTE)是一个命名的临时结果集,存在于单个语句的范围内,定义后能够在该语句中引用它,可能屡次引用。下面的讨论描述如何编写使用 CTE 的语句。mysql

通用表表达式sql

若要指定公共表表达式,请使用用逗号分隔子语句的 WITH 子句。每一个子句提供一个子查询,该子查询生成一个结果集,每一个子查询关联一个名称。如下示例在 WITH 子句中定义名为 cte1 和 cte2 的 CTE,并在 WITH 子句后面的顶级 SELECT 中引用它们:express

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

在包含 WITH 子句的语句中,能够引用每一个 CTE 名称来访问相应的 CTE 结果集。ide

一个 CTE 名称能够在其余 CTE 中引用,从而能够基于其余 CTE 定义 CTE。code

CTE 能够引用自身来定义递归 CTE。递归 CTE 的常见应用包括序列生成和层次或树结构数据的遍历。htm

公共表表达式是 DML 语句语法的可选部分。它们是使用 WITH 子句定义的:对象

1. with_clause:
2.     WITH [RECURSIVE]
3.         cte_name [(col_name [, col_name] ...)] AS (subquery)
4.         [, cte_name [(col_name [, col_name] ...)] AS (subquery)] ...

cte_name 命名一个公共表表达式,能够在包含 WITH 子句的语句中用做表引用。递归

AS (subquery) 的 subquery 部分称为“CTE 子查询”,它生成 CTE 结果集。AS 后面的括号是必需的。get

若是公共表表达式的子查询引用它本身的名称,则该表达式是递归的。若是 WITH 子句中的任何 CTE 是递归的,则必须包含 RECURSIVE 关键字。

明确给定 CTE 的列名以下:

● 若是圆括号括起来的列表名称跟在 CTE 名称后面,则这些名称就是列名称:

1. WITH cte (col1, col2) AS
2. (
3.   SELECT 1, 2
4.   UNION ALL
5.   SELECT 3, 4
6. )
7. SELECT col1, col2 FROM cte;

列表中的名称数量必须与结果集中的列数相同。

● 不然,列名来自 AS (subquery) 部分的第一个 SELECT 的选择列表:

1. WITH cte AS
2. (
3.   SELECT 1 AS col1, 2 AS col2
4.   UNION ALL
5.   SELECT 3, 4
6. )
7. SELECT col1, col2 FROM cte;

在如下上下文中容许使用 WITH 子句:

● 在 SELECT、UPDATE 和 DELETE 语句的开头。

1. WITH ... SELECT ...
2. WITH ... UPDATE ...
3. WITH ... DELETE ...

● 在子查询(包括派生表子查询)开始部分:

1.SELECT ... WHERE id IN (WITH ... SELECT ...) ...
2.SELECT * FROM (WITH ... SELECT ...) AS dt ...

● 紧跟在包含 SELECT 语句的 SELECT 语句以前:

1. INSERT ... WITH ... SELECT ...
2. REPLACE ... WITH ... SELECT ...
3. CREATE TABLE ... WITH ... SELECT ...
4. CREATE VIEW ... WITH ... SELECT ...
5. DECLARE CURSOR ... WITH ... SELECT ...
6. EXPLAIN ... WITH ... SELECT ...

同一级别只容许有一个 WITH 子句。同一级别的 WITH 后面跟 WITH 是不容许的,所以如下语句是非法的:

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

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

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

但若是出如今不一样的层级,一个语句能够包含多个WITH子句:

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

WITH 子句能够定义一个或多个公共表表达式,但每一个 CTE 名称对于该子句必须是惟一的。如下语句是非法的:

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

要使语句合法,请使用惟一名称定义 CTE:

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

CTE 能够指自身或其余 CTE:

● 自引用 CTE 是递归的。

● CTE 能够引用在同一 WITH 子句中前面定义的 CTE,但不能引用后面定义的 CTE。

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

● 给定查询块中的 CTE 能够引用在更外部层级的查询块中定义的 CTE,但不能引用在更内部层级的查询块中定义的 CTE。

为了解析对同名对象的引用,派生表隐藏 CTE;而 CTE 隐藏基本表、临时表和视图。名称解析的方法是在同一个查询块中搜索对象,若是找不到具备该名称的对象依次转到外部查询块。

与派生表同样,MySQL 8.0.14 以前 CTE 不能包含外部引用。这是 MySQL 8.0.14 中取消的 MySQL 限制,而不是 SQL 标准的限制。

官方网址:
https://dev.mysql.com/doc/refman/8.0/en/with.html

相关文章
相关标签/搜索