mysql - 在我的 sql < 8 中获取树文件夹结构的父母和孩子,并且没有 CTE
问题描述
id
我有一个文件夹表,它以,parent_id
关系连接到自身:
CREATE TABLE folders (
id int(10) unsigned NOT NULL AUTO_INCREMENT,
title nvarchar(255) NOT NULL,
parent_id int(10) unsigned DEFAULT NULL,
PRIMARY KEY (id)
);
INSERT INTO folders(id, title, parent_id) VALUES(1, 'root', null);
INSERT INTO folders(id, title, parent_id) values(2, 'one', 1);
INSERT INTO folders(id, title, parent_id) values(3, 'target', 2);
INSERT INTO folders(id, title, parent_id) values(4, 'child one', 3);
INSERT INTO folders(id, title, parent_id) values(5, 'child two', 3);
INSERT INTO folders(id, title, parent_id) values(6, 'root 2', null);
INSERT INTO folders(id, title, parent_id) values(7, 'other child one', 6);
INSERT INTO folders(id, title, parent_id) values(8, 'other child two', 6);
我想要一个查询,它返回该记录的所有父母,直接回到路线和任何孩子。
因此,如果我要求带有 的文件夹id=3
,我会得到记录:1, 2, 3, 4, 5
。我很困惑如何得到父母。
MYSQL 的版本是 5.7,并且没有立即升级的计划,所以遗憾的是 CTE 不是一个选项。
我已经创建了这个sql fiddle
解决方案
在您的表设计中,ID
对应PARENT_ID
于“邻接表模型”,用于存储一棵树。
还有另一种设计,称为“嵌套集模型”,它可以更轻松地在此处执行您想要的操作。
请参阅 Mike Hillyer 的这篇出色的文章,描述两者:management -hierarchical-data-in-mysql
总之:
树存储在如下表中:
CREATE TABLE nested_category (
category_id INT AUTO_INCREMENT PRIMARY KEY,
name VARCHAR(20) NOT NULL,
lft INT NOT NULL,
rgt INT NOT NULL
);
查找从根到给定节点的路径(此处为“FLASH”):
SELECT parent.name
FROM nested_category AS node,
nested_category AS parent
WHERE node.lft BETWEEN parent.lft AND parent.rgt
AND node.name = 'FLASH'
ORDER BY parent.lft;
查找给定节点的所有子节点(此处为“便携式电子设备”):
SELECT node.name, (COUNT(parent.name) - (sub_tree.depth + 1)) AS depth
FROM nested_category AS node,
nested_category AS parent,
nested_category AS sub_parent,
(
SELECT node.name, (COUNT(parent.name) - 1) AS depth
FROM nested_category AS node,
nested_category AS parent
WHERE node.lft BETWEEN parent.lft AND parent.rgt
AND node.name = 'PORTABLE ELECTRONICS'
GROUP BY node.name
ORDER BY node.lft
)AS sub_tree
WHERE node.lft BETWEEN parent.lft AND parent.rgt
AND node.lft BETWEEN sub_parent.lft AND sub_parent.rgt
AND sub_parent.name = sub_tree.name
GROUP BY node.name
HAVING depth <= 1
ORDER BY node.lft;
重命名为您的文件夹表后
- TABLE nested_category -> TABLE 文件夹
- 列 category_id -> 列 id
- 列名 -> 列标题
解决方案是:
CREATE TABLE folders (
id INT AUTO_INCREMENT PRIMARY KEY,
title VARCHAR(20) NOT NULL,
lft INT NOT NULL,
rgt INT NOT NULL
);
INSERT INTO folders(id, title, lft, rgt) values(1, 'root', 1, 10);
INSERT INTO folders(id, title, lft, rgt) values(2, 'one', 2, 9);
INSERT INTO folders(id, title, lft, rgt) values(3, 'target', 3, 8);
INSERT INTO folders(id, title, lft, rgt) values(4, 'child one', 4, 5);
INSERT INTO folders(id, title, lft, rgt) values(5, 'child two', 6, 7);
INSERT INTO folders(id, title, lft, rgt) values(6, 'root 2', 11, 16);
INSERT INTO folders(id, title, lft, rgt) values(7, 'other child one', 12, 13);
INSERT INTO folders(id, title, lft, rgt) values(8, 'other child two', 14, 15);
目标路径:
SELECT parent.title
FROM folders AS node,
folders AS parent
WHERE node.lft BETWEEN parent.lft AND parent.rgt
AND node.title = 'target'
ORDER BY parent.lft;
目标儿童:
SELECT node.title, (COUNT(parent.title) - (sub_tree.depth + 1)) AS depth
FROM folders AS node,
folders AS parent,
folders AS sub_parent,
(
SELECT node.title, (COUNT(parent.title) - 1) AS depth
FROM folders AS node,
folders AS parent
WHERE node.lft BETWEEN parent.lft AND parent.rgt
AND node.title = 'target'
GROUP BY node.title
ORDER BY node.lft
)AS sub_tree
WHERE node.lft BETWEEN parent.lft AND parent.rgt
AND node.lft BETWEEN sub_parent.lft AND sub_parent.rgt
AND sub_parent.title = sub_tree.title
GROUP BY node.title
HAVING depth <= 1
ORDER BY node.lft;
要在单个查询中获取所有数据,union
应该这样做。
推荐阅读
- python - Python:将文件中的字符串与字符串文字连接起来
- amazon-web-services - AWS Amplify 在 API 请求中使用访客凭证,而不是经过身份验证的凭证
- c# - C# 中是否有“when()”语句或等效语句?
- dart - 如何使用 dartdoc 生成类似 docs.flutter.io 的 Flutter 文档?
- python - 从具有多个参数的函数定义列表
- android - FastScrolling recyclerView 与 PagedListAdapter
- download - 使用 fullcalendar 下载 ics 文件
- php - 使用 PHP 持续检查文件是否存在
- php - PHP如何让搜索引擎使用标签和LIKE
- vue.js - 包括来自模块的静态资产