求知 文章 文库 Lib 视频 iPerson 课程 认证 咨询 工具 讲座 Model Center   模型库  
会员   
 


AI 智能化软件测试方法与实践
5月23-24日 上海+在线



人工智能.机器学习TensorFlow
5月22-23日 北京



图数据库与知识图谱
5月22-23日 北京
 
 

mysql教程
MySQL快速学习入门
MySQL是什么
MySQL安装
MySQL示例数据库
MySQL导入示例数据库
MySQL基础教程
MySQL查询数据
MySQL WHERE语句
MySQL插入数据
MySQL更新表数据
MySQL删除表数据
MySQL创建与删除数据库
MySQL创建表
MySQL修改表结构
MySQL重命名表
MySQL数据类型
高级部分
MySQL技巧
MySQL存储过程
MySQL视图
MySQL触发器
MySQL管理
MySQL全文搜索
MySQL函数
应用程序连接
MySQL+Node.js连接和操作
Python+MySQL连接和操作
 
 

MySQL递归CTE(公共表表达式)
654 次浏览
8次  

在本教程中,您将了解MySQL递归CTE(公共表表达式)以及如何使用它来遍历分层数据。

自MySQL 8.0版以来简要介绍了公共表表达式或叫CTE的功能,因此需要您在计算机上安装MySQL 8.0,以便在本教程中练习本语句。

1. MySQL递归CTE简介

递归公用表表达式(CTE)是一个具有引用CTE名称本身的子查询的CTE。以下说明递归CTE的语法 -

WITH RECURSIVE cte_name AS (
initial_query -- anchor member
UNION ALL
recursive_query -- recursive member that references to the CTE name
)
SELECT * FROM cte_name;

递归CTE由三个主要部分组成:

形成CTE结构的基本结果集的初始查询(initial_query),初始查询部分被称为锚成员。

递归查询部分是引用CTE名称的查询,因此称为递归成员。递归成员由一个UNION ALL或UNION DISTINCT运算符与锚成员相连。

终止条件是当递归成员没有返回任何行时,确保递归停止。

递归CTE的执行顺序如下:

首先,将成员分为两个:锚点和递归成员。

接下来,执行锚成员形成基本结果集(R0),并使用该基本结果集进行下一次迭代。

然后,将Ri结果集作为输入执行递归成员,并将Ri+1作为输出。

之后,重复第三步,直到递归成员返回一个空结果集,换句话说,满足终止条件。

最后,使用UNION ALL运算符将结果集从R0到Rn组合。

2. 递归成员限制

递归成员不能包含以下结构:

聚合函数,如MAX,MIN,SUM,AVG,COUNT等

GROUP BY子句

ORDER BY子句

LIMIT子句

DISTINCT

请注意,上述约束不适用于锚定成员。 另外,只有在使用UNION运算符时,要禁止DISTINCT才适用。 如果使用UNION DISTINCT运算符,则允许使用DISTINCT。

另外,递归成员只能在其子句中引用CTE名称,而不是引用任何子查询。

3. 简单的MySQL递归CTE示例

请参阅以下简单的递归CTE 示例:

WITH RECURSIVE cte_count (n)
AS (
SELECT 1
UNION ALL
SELECT n + 1
FROM cte_count
WHERE n < 3
)
SELECT n
FROM cte_count;

在此示例中,以下查询:

SELECT 1

是作为基本结果集返回1的锚成员。

以下查询 -

SELECT n + 1
FROM cte_count
WHERE n < 3

是递归成员,因为它引用了cte_count的CTE名称。

递归成员中的表达式<3是终止条件。当n等于3,递归成员将返回一个空集合,将停止递归。

下图显示了上述CTE的元素:

递归CTE返回以下输出:

递归CTE的执行步骤如下:

首先,分离锚和递归成员。

接下来,锚定成员形成初始行(SELECT 1),因此第一次迭代在n = 1时产生1 + 1 = 2。

然后,第二次迭代对第一次迭代的输出(2)进行操作,并且在n = 2时产生2 + 1 = 3。

之后,在第三次操作(n = 3)之前,满足终止条件(n <3),因此查询停止。

最后,使用UNION ALL运算符组合所有结果集1,2和3。

4. 使用MySQL递归CTE遍历分层数据

我们将使用示例数据库(yiibaidb)中的employees表进行演示。

mysql> desc employees;
+----------------+--------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+----------------+--------------+------+-----+---------+-------+
| employeeNumber | int(11) | NO | PRI | NULL | |
| lastName | varchar(50) | NO | | NULL | |
| firstName | varchar(50) | NO | | NULL | |
| extension | varchar(10) | NO | | NULL | |
| email | varchar(100) | NO | | NULL | |
| officeCode | varchar(10) | NO | MUL | NULL | |
| reportsTo | int(11) | YES | MUL | NULL | |
| jobTitle | varchar(50) | NO | | NULL | |
+----------------+--------------+------+-----+---------+-------+
8 rows in set

employees表具有引用employeeNumber字段的reportsTo字段。 reportsTo列存储经理的ID。总经理不会向公司的组织结构中的任何人报告,因此reportsTo列中的值为NULL。

您可以应用递归CTE以自顶向下的方式查询整个组织结构,如下所示:

WITH RECURSIVE employee_paths AS
( SELECT employeeNumber,
reportsTo managerNumber,
officeCode,
1 lvl
FROM employees
WHERE reportsTo IS NULL
UNION ALL
SELECT e.employeeNumber,
e.reportsTo,
e.officeCode,
lvl+1
FROM employees e
INNER JOIN employee_paths ep ON ep.employeeNumber = e.reportsTo )
SELECT employeeNumber,
managerNumber,
lvl,
city
FROM employee_paths ep
INNER JOIN offices o USING (officeCode)
ORDER BY lvl, city;

让我们将查询分解成更小的部分,使其更容易理解。

首先,使用以下查询形成锚成员:

SELECT
employeeNumber, reportsTo managerNumber, officeCode
FROM
employees
WHERE
reportsTo IS NULL

此查询(锚成员)返回reportTo为NULL的总经理。

其次,通过引用CTE名称来执行递归成员,在这个示例中为 employee_paths:

SELECT
e.employeeNumber, e.reportsTo, e.officeCode
FROM
employees e
INNER JOIN
employee_paths ep ON ep.employeeNumber = e.reportsTo

此查询(递归成员)返回经理的所有直接上级,直到没有更多的直接上级。 如果递归成员不返回直接上级,则递归停止。

第三,使用employee_paths的查询将CTE返回的结果集与offices表结合起来,以得到最终结果集合。

以下是查询的输出:

在本教程中,您已经了解了MySQL递归CTE以及如何使用它来遍历分层数据。


您可以捐助,支持我们的公益事业。

1元 10元 50元





认证码: 验证码,看不清楚?请点击刷新验证码 必填



654 次浏览
8次
 捐助