MySQL 中的递归查询:根据父节点查询子节点

在数据库设计中,树形结构非常常见,比如组织结构、目录结构等。在 MySQL 中,可以使用递归查询来获取某一父节点下的所有子节点。本文将详细介绍如何使用 SQL 实现这种查询,并附上代码示例和相应的关系图及类图。

数据库表结构

首先,假设我们有一个简单的表结构来表示树形关系,表结构如下:

CREATE TABLE categories (
    id INT AUTO_INCREMENT PRIMARY KEY,
    name VARCHAR(100) NOT NULL,
    parent_id INT,
    FOREIGN KEY (parent_id) REFERENCES categories(id)
);
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.

在这个 categories 表中,id 是每个分类的唯一标识,name 是分类的名称,parent_id 用于指向其父分类的 ID。

示例数据

我们插入一些示例数据:

INSERT INTO categories (name, parent_id) VALUES
('Root Category', NULL),
('Subcategory 1', 1),
('Subcategory 2', 1),
('Subcategory 1.1', 2),
('Subcategory 1.2', 2),
('Subcategory 2.1', 3);
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.

这个例子包含了一棵包含根节点和多个子节点的树。

递归查询子节点

在 MySQL 中,虽然从版本 8.0 开始支持公共表表达式(CTE),可以很方便的实现递归查询,但在较早版本中,我们一般使用自连接。以下是使用 CTE 实现递归查询的例子。

使用公共表表达式(CTE)
WITH RECURSIVE CategoryCTE AS (
    SELECT id, name, parent_id
    FROM categories
    WHERE id = 1  -- 假设我们查询根节点的子节点

    UNION ALL

    SELECT c.id, c.name, c.parent_id
    FROM categories c
    INNER JOIN CategoryCTE ct ON ct.id = c.parent_id
)
SELECT * FROM CategoryCTE;
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.

在这个代码中,我们首先选择了 ID 为 1 的类别(根节点),然后通过自我连接将所有子节点不断加入到结果集中。

自连接方法(适用于老版本)

对于 MySQL 5.x 及之前的版本,我们可以使用自连接来遍历,以一种较为繁琐的方式来实现:

SELECT * FROM categories AS c1
WHERE c1.parent_id = 1
UNION ALL
SELECT c2.* FROM categories AS c1
JOIN categories AS c2 ON c1.id = c2.parent_id
WHERE c1.parent_id = 1;
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.

这种方法不够灵活,特别是对于多层次的树形结构,但在没有 CTE 的情况下我们常常不得不这样做。

关系图

以下是基于我们的 categories 表所表示的关系图:

CATEGORIES INT id PK VARCHAR name INT parent_id has

类图

为了更好地理解这个结构,我们还可以用类图表示:

Category +int id +String name +int parent_id +List children

结论

通过以上的方法,我们能够有效地在 MySQL 数据库中实现根据父节点递归查询子节点的需求。无论是使用 CTE 还是自连接,这种查询方式可以帮助我们处理各种树形数据结构,解决不同场景下的数据查询需求。希望本文能对你在使用 MySQL 进行树形结构查询时有所帮助!