我使用的是MySQL,是否可以从下面的表结构中通过单个SQL语句获得以下结果?
目前,我可以通过在 PHP 代码中使用逻辑 while 循环来获得相同的结果。如果我能在单个 SQL 中实现,那么对于性能来说就很好了。
预期结果:
|----------+-----------------------------------------------+
| Id (PK) + headerANDsubheader +
|----------+-----------------------------------------------+
| 1 + A-head +
| 4 + -A-head-A1-subHead +
| 5 + -A-head-A2-subHead +
| 6 + --A-head-A1-subHead-A1.1-subHead +
| 7 + --A-head-A1-subHead-A1.2-subHead +
列 Id
是主键。如果父键为 0,则表示其根级别标题。
如果ParentKey
不等于0,则表示它是某人的子标题,而ParentKey
是该子标题的指针。
表:Header_sub
|----------+-----------------------------------------------+------------+
| Id (PK) + headerANDsubheader + ParentKey +
|----------+-----------------------------------------------+------------+
| 1 + A-head + 0 +
|----------+-----------------------------------------------+------------+
| 2 + B-head + 0 +
|----------+-----------------------------------------------+------------+
| 3 + C-head + 0 +
|----------+-----------------------------------------------+------------+
| 4 + A-head-A1-subHead + 1 +
|----------+-----------------------------------------------+------------+
| 5 + A-head-A2-subHead + 1 +
|----------+-----------------------------------------------+------------+
| 6 + A-head-A1-subHead-A1.1-subHead + 4 +
|----------+-----------------------------------------------+------------+
| 7 + A-head-A1-subHead-A1.2-subHead + 4 +
|----------+-----------------------------------------------+------------+
我正在尝试这样...
SELECT
CONCAT(REPEAT(' ', (COUNT(parent.subject_group_name) - 1) ), node.subject_group_name) AS name
FROM
major_scholastic as node,
major_scholastic as parent
WHERE
node.s_gid BETWEEN parent.s_gid AND parent.parent_id
GROUP BY node.subject_group_name
ORDER BY node.s_gid
最佳答案
您的headerANDsubheader
列是某种物化路径。这允许您通过使用带有 LIKE
条件的 JOIN
来获取所有祖先(不仅仅是直接父代)。
以下查询演示了如何获取不同任务可能需要的信息:
select node.*
, group_concat(anc.Id order by char_length(anc.headerANDsubheader)) as idPath
, group_concat(lpad(anc.Id, 10, 0) order by char_length(anc.headerANDsubheader)) as idPathSortable
, count(anc.Id) as depthLevel
, concat(repeat('- ', count(anc.Id)-1), node.headerANDsubheader) as indendtedHeader
from header_sub node
join header_sub anc
on node.headerANDsubheader like concat(anc.headerANDsubheader, '%')
group by node.Id
order by idPathSortable
结果如下所示:
| Id | headerANDsubheader | ParentKey | idPath | idPathSortable | depthLevel | indendtedHeader |
|----|--------------------------------|-----------|--------|----------------------------------|------------|------------------------------------|
| 1 | A-head | 0 | 1 | 0000000001 | 1 | A-head |
| 4 | A-head-A1-subHead | 1 | 1,4 | 0000000001,0000000004 | 2 | - A-head-A1-subHead |
| 6 | A-head-A1-subHead-A1.1-subHead | 4 | 1,4,6 | 0000000001,0000000004,0000000006 | 3 | - - A-head-A1-subHead-A1.1-subHead |
| 7 | A-head-A1-subHead-A1.2-subHead | 4 | 1,4,7 | 0000000001,0000000004,0000000007 | 3 | - - A-head-A1-subHead-A1.2-subHead |
| 5 | A-head-A2-subHead | 1 | 1,5 | 0000000001,0000000005 | 2 | - A-head-A2-subHead |
| 2 | B-head | 0 | 2 | 0000000002 | 1 | B-head |
| 3 | C-head | 0 | 3 | 0000000003 | 1 | C-head |
现在只需迈出一小步即可获得您需要的结果:
select node.Id, concat(
repeat(' ', count(anc.Id)-1),
repeat('-', count(anc.Id)-1),
node.headerANDsubheader
) as indendtedHeader
from header_sub node
join header_sub anc
on node.headerANDsubheader like concat(anc.headerANDsubheader, '%')
group by node.Id
order by group_concat(lpad(anc.Id, 10, 0) order by char_length(anc.headerANDsubheader))
结果:
| Id | indendtedHeader |
|----|------------------------------------|
| 1 | A-head |
| 4 | -A-head-A1-subHead |
| 6 | --A-head-A1-subHead-A1.1-subHead |
| 7 | --A-head-A1-subHead-A1.2-subHead |
| 5 | -A-head-A2-subHead |
| 2 | B-head |
| 3 | C-head |
更新:
join header_sub anc
on node.headerANDsubheader like concat(anc.headerANDsubheader, '%')
anc
是“ancestor”的缩写。我们希望将每个节点与其所有祖先(包括其自身)连接起来。该条件可以理解为 anc.headerANDsubheader IS PREFIX OF node.headerANDsubheader
。因此“A-head-A1-subHead-A1.1-subHead”将与“A-head”、“A-head-A1-subHead”和“A-head-A1-subHead-A1.1-subHead”连接”。通过 node.id
对结果进行分组,我们可以使用聚合 COUNT
来获取深度级别,并使用 GROUP_CONCAT
来生成有用的路径。不过,最好将深度和路径存储在表中,这样我们就根本不需要连接。
关于mysql - 没有存储过程的树层次查询,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/38813091/