4

我有一个 column id,一个 columnparent和一个 column path,它是一个物化路径。

看起来像

1  | \N | 1  
2  | 1  | 1/2  
3  | 2  | 1/2/3  
4  | 3  | 1/2/3/4  
5  | 3  | 1/2/3/5  
6  | 2  | 1/2/6  
7  | 6  | 1/2/6/7  
8  | 2  | 1/2/8  
9  | 1  | 1/9  
10 | 9  | 1/9/10  
11 | 10 | 1/9/10/11  
12 | 11 | 1/9/10/11/12  
13 | 11 | 1/9/10/11/13  
14 | 11 | 1/9/10/11/14  
15 | 14 | 1/9/10/11/14/15  
16 | 14 | 1/9/10/11/14/16  
17 | 14 | 1/9/10/11/14/17  
18 | 10 | 1/9/10/18  
19 | \N | 19  
20 | 19 | 19\20  
21 | 19 | 19\21

我需要根据这张表做一些查询。

我需要做的查询是


选择所有id9岁的孩子

SELECT * FROM `tester` WHERE 'path' LIKE '%/9/%';  

可以正常工作,直到您将 ID 替换为 1 或 19,因为/一开始没有。

SELECT * FROM `tester` WHERE 'path' LIKE '%1/%';

将选择数字以 1 结尾的所有行,因此,1、11、21、31、211 等

SELECT * FROM `tester` WHERE 'path' LIKE '1/%';

对于第 1 行或第 19 行都可以正常工作

所以SELECT * FROM测试仪WHERE 'path' LIKE '1/%' OR 'path' LIKE '%/1/%'
是我能想到的最好的,有什么建议吗?



为此Select * from测试人员选择 9 个的直接子代,但不选择子代where 'parent' = 9;会正常工作。


选择 9 个孩子的总数,x 层深。

所以我想以一行level1, level2, level3, ... levelx或 x 行结束,代表不同的级别,

让我们假设此示例的 x 为 3 此示例中的行将是9, 8, 6(如果我们要求,第 4 级将是 3)

有任何想法吗?

编辑

#select count of children of specific node(5) down to a maximum of three levels, do no include the parent
SELECT COUNT(child.id) children, 
LENGTH(REPLACE(child.path, parent.path, '')) - LENGTH(REPLACE(REPLACE(child.path, parent.path, ''), '/', '')) AS LEVEL
FROM `tester` child JOIN `tester` parent ON child.path LIKE CONCAT(parent.path,'%') 
WHERE parent.id  =5 
GROUP BY LEVEL HAVING LEVEL <= 3 AND LEVEL > 0;


**选择 9 的孩子的 id 到 x 级别,与 9 相关的级别,

所以在这个例子中,我们将再次使用 3 作为 x。

我们正在寻找回来

10 | 1
11 | 2
18 | 2
12 | 3
13 | 3
14 | 3 

我再次完全不知道如何做到这一点。

编辑:

#select all information, and relative level from parent of children of specific node(5) down to a maximum of three levels, do no include the parent
SELECT child.*, 
LENGTH(REPLACE(child.path, parent.path, '')) - LENGTH(REPLACE(REPLACE(child.path, parent.path, ''), '/', '')) AS LEVEL
FROM `tester` child JOIN `tester` parent ON child.path LIKE CONCAT(parent.path,'%') 
WHERE parent.id  =9 
GROUP BY id HAVING LEVEL <= 3 AND LEVEL > 0;
4

1 回答 1

2

提醒您一下,这些解决方案基于字符串比较,未优化且无法使用索引。你应该考虑以不同的方式规范你的表格。(请参阅在 MySQL 中管理分层数据

关于一些问题:


选择 id 9 的所有孩子:

由于该Path列不包括前导和尾随斜杠,因此您需要将它们连接到路径:

SELECT * 
FROM tester
WHERE CONCAT('/', path, '/') LIKE '%/9/%';

选择 9 个孩子的总数,x 层深:

我们需要按路径中的斜线数减去父路径中的斜线数进行分组:

SELECT (LENGTH(c.Path) - LENGTH(REPLACE(c.Path, '/', '')))
    - (LENGTH(p.Path) - LENGTH(REPLACE(p.Path, '/', ''))) AS Level,
    COUNT(*)
FROM tester c
    JOIN tester p ON c.Parent = p.ID
WHERE CONCAT('/', path, '/') LIKE '%/9/%';
GROUP BY 1

为简单起见,我使用上面的查询来显示所有级别,如果您想限制 x 级别的深度,请使用WHERE下面查询中的谓词。


选择 9 的孩子的 id 到 x 级别,级别相对于 9:

我们将Path列搜索到 ax 个级别,同时考虑到父母级别:

SELECT c.*
FROM tester c
    JOIN tester p ON c.Parent = p.ID
WHERE CONCAT(
    '/',
    SUBSTRING_INDEX(
        Path, 
        '/', 
        (LENGTH(p.Path) - LENGTH(REPLACE(p.Path, '/', ''))) + 4
    ),
'/') LIKE '%/9/%'

我们正在采取的步骤:

  1. 我们需要找出父级的深度,我们可以通过计算父级路径中的斜线来找到它。( LENGTH(p.Path) - LENGTH(REPLACE(p.Path, '/', '')))
  2. 我们需要在这个数字上加 1,因为带有 1 个斜线的路径有 2 层深。
  3. 我们添加 x 个所需的级别。
  4. 将路径列抓取到总级别,(使用该SUBSTRING_INDEX功能)。
  5. 添加前导和尾随斜杠。
  6. 在最后一个字符串中搜索 9。
于 2011-06-14T00:18:05.717 回答