在涉及层级结构的数据统计场景中,比如组织架构统计、商品分类销量汇总、部门业绩核算等,经常需要基于父级节点统计其下所有子节点的相关数据,或者根据存储的路径信息查找对应的子节点集合,这类需求可以通过SQL嵌套查询高效实现。

基础场景与表结构设计
首先我们设计一个典型的层级结构表,用于存储分类信息,包含分类ID、分类名称、父级分类ID、分类路径四个核心字段,路径字段存储从根节点到当前节点的所有ID拼接结果,方便后续路径查找操作。
-- 创建分类表
CREATE TABLE category (
id INT PRIMARY KEY,
name VARCHAR(50) NOT NULL,
parent_id INT,
path VARCHAR(255)
);
-- 插入测试数据,路径格式为/根ID/父ID/当前ID
INSERT INTO category (id, name, parent_id, path) VALUES
(1, '数码产品', 0, '/1'),
(2, '手机', 1, '/1/2'),
(3, '电脑', 1, '/1/3'),
(4, '智能手机', 2, '/1/2/4'),
(5, '功能手机', 2, '/1/2/5'),
(6, '笔记本电脑', 3, '/1/3/6'),
(7, '台式电脑', 3, '/1/3/7');
基于父级的递归统计实现
递归统计的核心需求是,给定一个父级ID,统计该父级下所有子节点的数量或者汇总子节点的其他属性。我们可以通过嵌套查询先获取所有子节点的ID集合,再基于这个集合做统计操作。
统计指定父级下所有子节点数量
首先通过子查询获取目标父级下的所有子节点ID,再在外层查询中统计数量。这里利用路径字段的前缀匹配特性,快速筛选出所有子节点。
-- 统计ID为1的数码产品分类下所有子节点数量 SELECT COUNT(*) AS child_count FROM category WHERE path LIKE (SELECT CONCAT(path, '/%') FROM category WHERE id = 1);
上述查询中,内层子查询先获取ID为1的分类的路径/1,拼接上/%之后得到/1/%,外层查询通过LIKE匹配所有路径以/1/开头的记录,也就是所有子节点,最后统计数量。
汇总子节点的关联数据
如果分类表关联了销量表,需要统计父级下所有子节点的总销量,可以通过嵌套查询关联两张表实现。
-- 创建销量表
CREATE TABLE category_sales (
category_id INT,
sales_num INT
);
-- 插入销量测试数据
INSERT INTO category_sales (category_id, sales_num) VALUES
(2, 100),
(3, 200),
(4, 50),
(5, 30),
(6, 120),
(7, 80);
-- 统计数码产品分类下所有子节点的总销量
SELECT SUM(cs.sales_num) AS total_sales
FROM category_sales cs
WHERE cs.category_id IN (
SELECT id
FROM category
WHERE path LIKE (SELECT CONCAT(path, '/%') FROM category WHERE id = 1)
);
这里内层嵌套查询先获取数码产品分类的所有子节点ID集合,外层查询通过IN条件筛选出这些ID对应的销量记录,最后求和得到总销量。
通过路径查找子查询的实现
除了基于父级ID统计,很多时候我们需要根据路径信息直接查找对应的子节点集合,比如已知某个分类的路径,查找其下所有子分类的详细信息,同样可以通过嵌套查询实现。
根据路径前缀查找子节点
路径字段存储了层级关系,只要子节点的路径包含父节点的路径作为前缀,就说明该节点是父节点的后代。我们可以通过嵌套查询先解析路径条件,再匹配对应的子节点。
-- 根据路径/1/2查找其下所有子分类的详细信息
SELECT id, name, parent_id, path
FROM category
WHERE path LIKE (
SELECT CONCAT(path, '/%')
FROM category
WHERE path = '/1/2'
);
该查询中,内层子查询根据输入的路径/1/2找到对应的分类,拼接出子节点路径前缀/1/2/%,外层查询匹配所有符合该前缀的路径记录,返回所有子分类的信息。
路径查找与统计结合
我们也可以将路径查找和统计需求结合,比如查找路径为/1/3的分类下所有子节点的平均销量。
-- 查找电脑分类下所有子节点的平均销量
SELECT AVG(cs.sales_num) AS avg_sales
FROM category_sales cs
WHERE cs.category_id IN (
SELECT id
FROM category
WHERE path LIKE (
SELECT CONCAT(path, '/%')
FROM category
WHERE path = '/1/3'
)
);
注意事项
- 路径字段需要保证格式统一,建议所有路径都以
/开头,并且层级之间用/分隔,避免匹配错误。 - 如果层级深度非常大,路径字段的长度需要预留足够,避免存储截断。
- 对于没有路径字段的表,也可以通过自连接的方式实现递归统计,但性能会比路径匹配的方式差,适合层级较浅的场景。
- 嵌套查询的性能取决于子查询返回的结果集大小,如果子查询结果集过大,建议先对子查询结果做索引优化。
使用嵌套查询实现递归统计和路径查找的核心是利用层级关系的存储特性,通过子查询先获取目标范围,再在外层做具体的统计或者查询操作,逻辑清晰且容易维护。