当前位置:首页 > 问答 > 正文

MySQL 父子关系:获取用于父子关系的MySQL查询CONCAT用法示例

MySQL | 父子关系:获取用于父子关系的MySQL查询CONCAT用法示例

场景引入

假设你在管理一个电商平台的商品分类系统,分类结构是多层级的——电子产品"下面有"手机","手机"下面又有"苹果"和"安卓",这种父子关系的数据怎么在MySQL里优雅地查询和展示呢?特别是当你需要把多级分类名称拼接成完整路径时(如"电子产品 > 手机 > 苹果"),CONCAT函数就是你的好帮手。

今天我们就来聊聊如何用MySQL处理父子关系数据,重点是通过CONCAT实现层级拼接的技巧。


基础表结构

先建个简单的分类表,存储父子关系:

CREATE TABLE categories (
    id INT AUTO_INCREMENT PRIMARY KEY,
    name VARCHAR(100) NOT NULL,
    parent_id INT NULL,
    FOREIGN KEY (parent_id) REFERENCES categories(id)
);

插入一些示例数据:

INSERT INTO categories (name, parent_id) VALUES 
('电子产品', NULL),
('手机', 1),
('苹果', 2),
('安卓', 2),
('笔记本电脑', 1),
('游戏本', 5),
('轻薄本', 5);

基础查询:直接父子关系

先查直接父子关系(比如查"手机"的子分类):

SELECT child.name AS child_name
FROM categories parent
JOIN categories child ON child.parent_id = parent.id
WHERE parent.name = '手机';

结果:

MySQL 父子关系:获取用于父子关系的MySQL查询CONCAT用法示例

+------------+
| child_name |
+------------+
| 苹果       |
| 安卓       |
+------------+

进阶:使用CONCAT拼接路径

固定层级拼接(已知层级深度)

如果明确知道最多3级分类,可以硬编码拼接:

SELECT 
    CONCAT(
        IFNULL(grandparent.name, ''), 
        IF(grandparent.name IS NOT NULL, ' > ', ''),
        IFNULL(parent.name, ''), 
        IF(parent.name IS NOT NULL, ' > ', ''),
        child.name
    ) AS full_path
FROM categories child
LEFT JOIN categories parent ON child.parent_id = parent.id
LEFT JOIN categories grandparent ON parent.parent_id = grandparent.id
WHERE child.name = '苹果';

结果:

+-----------------------+
| full_path             |
+-----------------------+
| 电子产品 > 手机 > 苹果 |
+-----------------------+

动态层级拼接(递归CTE)

MySQL 8.0+支持递归CTE,适合不确定层级的场景:

WITH RECURSIVE category_path AS (
    -- 基础查询:找出目标节点(如'苹果')
    SELECT id, name, parent_id, name AS path
    FROM categories
    WHERE name = '苹果'
    UNION ALL
    -- 递归部分:向上查找父节点
    SELECT c.id, c.name, c.parent_id, CONCAT(c.name, ' > ', cp.path)
    FROM categories c
    JOIN category_path cp ON c.id = cp.parent_id
)
SELECT path FROM category_path
ORDER BY LENGTH(path) DESC LIMIT 1;

结果:

MySQL 父子关系:获取用于父子关系的MySQL查询CONCAT用法示例

+-----------------------+
| path                  |
+-----------------------+
| 电子产品 > 手机 > 苹果 |
+-----------------------+

实用技巧

添加分隔符时的空值处理

IFNULL避免NULL值破坏拼接:

CONCAT(
    IFNULL(parent.name, ''), 
    IF(parent.name IS NOT NULL, ' > ', ''),
    child.name
)

反向路径拼接(子到根)

有时需要从子节点回溯到根节点:

WITH RECURSIVE category_tree AS (
    SELECT id, name, parent_id, name AS breadcrumb
    FROM categories
    WHERE name = '游戏本'
    UNION ALL
    SELECT c.id, c.name, c.parent_id, CONCAT(c.name, ' > ', ct.breadcrumb)
    FROM categories c
    JOIN category_tree ct ON c.id = ct.parent_id
)
SELECT breadcrumb FROM category_tree
WHERE parent_id IS NULL;

结果:

+----------------------------------+
| breadcrumb                       |
+----------------------------------+
| 电子产品 > 笔记本电脑 > 游戏本   |
+----------------------------------+

常见问题

Q:CONCAT和CONCAT_WS有什么区别?
A:CONCAT_WS会自动跳过NULL值并用指定分隔符连接,

MySQL 父子关系:获取用于父子关系的MySQL查询CONCAT用法示例

CONCAT_WS(' > ', grandparent.name, parent.name, child.name)

Q:MySQL 5.7以下版本怎么实现递归?
A:需要存储过程或应用层代码处理,无法纯SQL优雅解决。


通过CONCAT函数结合JOIN或递归CTE,可以灵活处理MySQL中的父子关系数据,关键点:

  1. 明确层级深度时,用多层LEFT JOIN硬编码
  2. 不确定深度时,MySQL 8.0+用递归CTE
  3. 注意处理NULL值,避免路径中出现"NULL >"

下次遇到商品分类、组织架构或评论回复这种层级数据时,试试这些方法吧!

发表评论