没有存储过程的树级分层查询

时间:2016-08-07 10:13:58

标签: mysql

我正在使用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是指针。{/ p>

表: 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

1 个答案:

答案 0 :(得分:0)

您的headerANDsubheader列是某种物化路径。这允许您使用JOIN条件LIKE来获取所有祖先(不仅是直接父级)。

以下查询演示了如何获取不同任务可能需要的信息:

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                             |

sqlfiddle

现在知道这是获得所需结果的一小步:

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                             |

sqlfiddle

<强>更新

join header_sub anc
    on node.headerANDsubheader like concat(anc.headerANDsubheader, '%')

anc是&#34; ancestor&#34;的快捷方式。我们希望将每个节点与其所有祖先(包括其自身)连接起来。条件可以读为anc.headerANDsubheader IS PREFIX OF node.headerANDsubheader。所以&#34; A-head-A1-subHead-A1.1-subHead&#34;将加入&#34; A-head&#34;,&#34; A-head-A1-subHead&#34;和&#34; A-head-A1-subHead-A1.1-subHead&#34;。按node.id对结果进行分组,我们可以使用聚合COUNT获取深度级别,GROUP_CONCAT生成有用的路径。但是,最好将深度和路径存储在表格中,因此我们根本不需要连接。