MySQL中的递归查询主要通过WITH RECURSIVE
语句来实现,这在处理具有层级关系或树形结构的数据时非常有用。下面将通过一个具体的例子来详细解释如何在MySQL中使用递归查询。
示例场景
假设我们有一个部门表(departments
),其中包含部门的ID、部门名称以及上级部门的ID(parent_id
)。现在,我们想要查询出某个部门及其所有下级部门的名称。
表结构
CREATE TABLE departments (
id INT AUTO_INCREMENT PRIMARY KEY,
name VARCHAR(255) NOT NULL,
parent_id INT,
FOREIGN KEY (parent_id) REFERENCES departments(id)
);
插入数据
INSERT INTO departments (name, parent_id) VALUES ('总公司', NULL);
INSERT INTO departments (name, parent_id) VALUES ('技术部', 1);
INSERT INTO departments (name, parent_id) VALUES ('人事部', 1);
INSERT INTO departments (name, parent_id) VALUES ('前端开发', 2);
INSERT INTO departments (name, parent_id) VALUES ('后端开发', 2);
INSERT INTO departments (name, parent_id) VALUES ('UI设计', 2);
最终表如下图:
递归查询
现在,如果我们想要查询出“技术部”及其所有下级部门的名称,可以使用以下SQL语句:
WITH RECURSIVE SubDeps AS (
-- 初始查询,选择顶级部门(技术部)
SELECT id, name, parent_id
FROM departments
WHERE name = '技术部'
UNION ALL
-- 递归查询,从当前已知部门中继续查询它们的下级部门
SELECT d.id, d.name, d.parent_id
FROM departments d
INNER JOIN SubDeps sd ON d.parent_id = sd.id
)
SELECT * FROM SubDeps;
查询结果如下图:
解释
- WITH RECURSIVE:这个语句开始了一个递归的公用表表达式(Common Table Expression, CTE)。
- SubDeps:这是CTE的名称,在递归查询中我们可以引用它。
- 初始查询:首先,我们从
departments
表中选择出顶级部门(这里是“技术部”)。 - UNION ALL:我们使用
UNION ALL
来合并初始查询的结果和递归查询的结果。UNION ALL
允许重复的行,如果确定不会有重复,也可以使用UNION
(但在这个例子中,由于我们可能查询出多个层级的相同部门,所以使用UNION ALL
)。 - 递归查询:在递归查询中,我们从
departments
表中再次选择数据,但这次我们选择的是那些其parent_id
等于CTE中当前行的id
的行。这样,我们就能找到所有下级部门。 - SELECT * FROM SubDeps:最后,我们从CTE中选择所有结果。