如何在纯 MySQL 中生成类别面包屑?
How can I generate a breadcrumb of Categories in pure MySQL?
假设我有 mdl_course_categories table:
select cat.id, cat.name, cat.parent, cat.depth, cat.path
from mdl_course_categories cat
| id | name | parent | depth | path |
|----|------|--------|-------|----------|
| 1 | a | 0 | 1 | /1 |
| 2 | b | 0 | 1 | /2 |
| 3 | c | 1 | 2 | /1/3 |
| 4 | d | 3 | 3 | /1/3/4 |
| 5 | e | 4 | 4 | /1/3/4/5 |
| 6 | f | 0 | 1 | /6 |
| 7 | g | 6 | 2 | /6/7 |
| 8 | h | 7 | 3 | /6/7/8 |
| 9 | i | 3 | 3 | /1/3/9 |
| 10 | j | 7 | 3 | /6/7/10 |
如何生成如下所示的面包屑?我是 SQL 的菜鸟,没有管理分层数据的经验。我查看了 this answer,但无法将其转换为我的 table 和情况。提前致谢!
| id | name | parent | depth | path | breadcrumb |
|----|------|--------|-------|----------|---------------|
| 1 | a | 0 | 1 | /1 | a |
| 2 | b | 0 | 1 | /2 | b |
| 3 | c | 1 | 2 | /1/3 | a - c |
| 4 | d | 3 | 3 | /1/3/4 | a - c - d |
| 5 | e | 4 | 4 | /1/3/4/5 | a - c - d - e |
| 6 | f | 0 | 1 | /6 | f |
| 7 | g | 6 | 2 | /6/7 | f - g |
| 8 | h | 7 | 3 | /6/7/8 | f - g - h |
| 9 | i | 3 | 3 | /1/3/9 | a - b - i |
| 10 | j | 7 | 3 | /6/7/10 | f - g - j |
WITH RECURSIVE
cte1 AS
(
SELECT 1 num
UNION ALL
SELECT num + 1
FROM cte1
WHERE num < ( SELECT MAX(LENGTH(path) - LENGTH(REPLACE(path, '/', '')))
FROM mdl_course_categories )
),
cte2 AS
(
SELECT cte1.num,
cat.*,
SUBSTRING_INDEX(SUBSTRING_INDEX(cat.path, '/', cte1.num+1), '/', -1) onechar
FROM cte1, mdl_course_categories cat
WHERE cte1.num <= (LENGTH(path) - LENGTH(REPLACE(cat.path, '/', '')))
),
cte3 AS
(
SELECT cte2.*, cat.name onecharname
FROM cte2, mdl_course_categories cat
WHERE cte2.onechar = cat.id
)
SELECT id, name, parent, depth, path, GROUP_CONCAT(onecharname ORDER BY num SEPARATOR ' - ') breadcrumb
FROM cte3
GROUP BY id, name, parent, depth, path;
当然可以压实,不过我觉得你自己也可以。
应@Shadow的要求,我也给出一个简单的解决方案
SELECT t1.id,
t1.name,
t1.parent,
t1.depth,
t1.path,
GROUP_CONCAT(t2.name ORDER BY LOCATE(CONCAT('/', t2.id, '/'), CONCAT(t1.path, '/')) SEPARATOR ' - ') breadcrumb
FROM mdl_course_categories t1,
mdl_course_categories t2
WHERE LOCATE(CONCAT('/', t2.id, '/'), CONCAT(t1.path, '/'))
GROUP BY t1.id,
t1.name,
t1.parent,
t1.depth,
t1.path;
PS。请记住,第一个是 O(N*AVG(M))
而第二个是 O(N*N)
- 其中 N
是记录数量,M
是树深度。
假设我有 mdl_course_categories table:
select cat.id, cat.name, cat.parent, cat.depth, cat.path
from mdl_course_categories cat
| id | name | parent | depth | path |
|----|------|--------|-------|----------|
| 1 | a | 0 | 1 | /1 |
| 2 | b | 0 | 1 | /2 |
| 3 | c | 1 | 2 | /1/3 |
| 4 | d | 3 | 3 | /1/3/4 |
| 5 | e | 4 | 4 | /1/3/4/5 |
| 6 | f | 0 | 1 | /6 |
| 7 | g | 6 | 2 | /6/7 |
| 8 | h | 7 | 3 | /6/7/8 |
| 9 | i | 3 | 3 | /1/3/9 |
| 10 | j | 7 | 3 | /6/7/10 |
如何生成如下所示的面包屑?我是 SQL 的菜鸟,没有管理分层数据的经验。我查看了 this answer,但无法将其转换为我的 table 和情况。提前致谢!
| id | name | parent | depth | path | breadcrumb |
|----|------|--------|-------|----------|---------------|
| 1 | a | 0 | 1 | /1 | a |
| 2 | b | 0 | 1 | /2 | b |
| 3 | c | 1 | 2 | /1/3 | a - c |
| 4 | d | 3 | 3 | /1/3/4 | a - c - d |
| 5 | e | 4 | 4 | /1/3/4/5 | a - c - d - e |
| 6 | f | 0 | 1 | /6 | f |
| 7 | g | 6 | 2 | /6/7 | f - g |
| 8 | h | 7 | 3 | /6/7/8 | f - g - h |
| 9 | i | 3 | 3 | /1/3/9 | a - b - i |
| 10 | j | 7 | 3 | /6/7/10 | f - g - j |
WITH RECURSIVE
cte1 AS
(
SELECT 1 num
UNION ALL
SELECT num + 1
FROM cte1
WHERE num < ( SELECT MAX(LENGTH(path) - LENGTH(REPLACE(path, '/', '')))
FROM mdl_course_categories )
),
cte2 AS
(
SELECT cte1.num,
cat.*,
SUBSTRING_INDEX(SUBSTRING_INDEX(cat.path, '/', cte1.num+1), '/', -1) onechar
FROM cte1, mdl_course_categories cat
WHERE cte1.num <= (LENGTH(path) - LENGTH(REPLACE(cat.path, '/', '')))
),
cte3 AS
(
SELECT cte2.*, cat.name onecharname
FROM cte2, mdl_course_categories cat
WHERE cte2.onechar = cat.id
)
SELECT id, name, parent, depth, path, GROUP_CONCAT(onecharname ORDER BY num SEPARATOR ' - ') breadcrumb
FROM cte3
GROUP BY id, name, parent, depth, path;
当然可以压实,不过我觉得你自己也可以。
应@Shadow的要求,我也给出一个简单的解决方案
SELECT t1.id,
t1.name,
t1.parent,
t1.depth,
t1.path,
GROUP_CONCAT(t2.name ORDER BY LOCATE(CONCAT('/', t2.id, '/'), CONCAT(t1.path, '/')) SEPARATOR ' - ') breadcrumb
FROM mdl_course_categories t1,
mdl_course_categories t2
WHERE LOCATE(CONCAT('/', t2.id, '/'), CONCAT(t1.path, '/'))
GROUP BY t1.id,
t1.name,
t1.parent,
t1.depth,
t1.path;
PS。请记住,第一个是 O(N*AVG(M))
而第二个是 O(N*N)
- 其中 N
是记录数量,M
是树深度。