我有一列id
,一列parent
和一列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
我需要根据此表进行一些查询。
我需要做的查询是
<小时/> 选择id
9 的所有子女
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/%'
;
我能提出最好的建议吗?
<小时/> 选择直接子女为9但不包括子女
Select * from
测试人员where 'parent' = 9
;会很好。
<小时/> 选择9个孩子的总计数,x深度。
所以我想最终得到一行level1, level2, level3, ... levelx
或x行,代表不同的等级,
让我们假设这个例子的x是3
此示例中的行将为9, 8, 6
(如果我们请求它将为3,则为第4级)
任何想法?
修改
#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;
答案 0 :(得分:1)
为了让您了解一下,这些解决方案基于字符串比较,未经过优化和优化。不能使用索引。您应该考虑以不同方式规范化表格。 (见Managing Hierarchical Data in MySQL)
关于一些问题:
选择所有ID为9的孩子:
由于Path
列不包含前导&amp;尾部斜杠,您需要将它们连接到路径:
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
列中搜索x个级别,同时考虑父级别:
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/%'
我们正在采取的步骤:
LENGTH(p.Path) - LENGTH(REPLACE(p.Path, '/', ''))
)SUBSTRING_INDEX
功能)。