【问题标题】:Tree-Hierarchical query without stored procedure没有存储过程的树层次查询
【发布时间】:2016-09-30 05:49:30
【问题描述】:

我正在使用 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

【问题讨论】:

  • 为什么查询和示例数据中的表名和列名不匹配?
  • 如果 header_sub 是您的实际表结构:为什么不在更新路径时将深度添加为列并在repeat 中使用它?

标签: mysql


【解决方案1】:

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

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

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 是“祖先”的快捷方式。我们希望将每个节点与其所有祖先(包括它自己)连接起来。条件可以读作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 来生成有用的路径。但是最好将深度和路径存储在表中,因此我们根本不需要连接。

【讨论】:

  • 感谢您的努力。但是,如果我的 headerANDsubheader 如下所示。如果我按以下方式更改数据,则它不起作用。它可以在 Id 上而不是 headerANDsubheader 值上吗? INSERT INTO Header_sub (Id, headerANDsubheader, ParentKey) VALUES (1, 'A head', 0), (2, 'B head', 0), (3, 'C head', 0), (4, 'subHead', 1), (5, 'A2 subHead', 1), (6, 'A1.1 subHead', 4), (7, 'A1.2 subHead', 4)
  • 那就不行了。您可以在表中添加一列来存储路径(如idPath 或在我的示例中更好的idPathSortable ),或者您将需要一个(递归)PHP 解决方案。 Here 你可以找到这样一个函数(最后一部分),它只使用一个简单的 SQL 查询来创建一个嵌套的 HTML 列表。
  • 好的,明白了。你能告诉我这部分查询是如何工作的吗...在 node.headerANDsubheader 上加入 header_sub anc,如 concat(anc.headerANDsubheader, '%')。为什么 LIKE concat(anc.headerANDsubheader, '%'),为什么不 = 而不是 like
  • 查看更新= 只会将每个节点与其自身连接。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2016-01-06
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多