Hai*_*ood 5 php mysql sql materialized-path-pattern
我有一个列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
Run Code Online (Sandbox Code Playgroud)
我需要根据这张表进行一些查询。
我需要做的查询是
id9 个孩子的所有孩子
SELECT * FROM `tester` WHERE 'path' LIKE '%/9/%';
Run Code Online (Sandbox Code Playgroud)
/可以正常工作,直到您将 ID 替换为 1 或 19,因为开头没有。
SELECT * FROM `tester` WHERE 'path' LIKE '%1/%';
Run Code Online (Sandbox Code Playgroud)
将选择数字以 1 结尾的所有行,因此,1、11、21、31、211 等
SELECT * FROM `tester` WHERE 'path' LIKE '1/%';
Run Code Online (Sandbox Code Playgroud)
对于第 1 行或第 19 行都可以正常工作
所以SELECT * FROM测试员WHERE 'path' LIKE '1/%' OR 'path' LIKE '%/1/%';
这是我能想到的最好的,有什么建议吗?
Select * from测试仪,选择 9 的直接子级,但不选择子级where 'parent' = 9;会工作得很好。
所以我想最终得到一行level1, level2, level3, ... levelx或 x 行,代表不同的级别,
让我们假设这个例子中的 x 是 3 这个例子中的行是9, 8, 6(如果我们要求的话,第四层是 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;
Run Code Online (Sandbox Code Playgroud)
因此,在这个例子中,我们将再次使用 3 作为 x。
我们正在寻找回来
10 | 1
11 | 2
18 | 2
12 | 3
13 | 3
14 | 3
Run Code Online (Sandbox Code Playgroud)
我再次完全不知道如何做到这一点。
编辑:
#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;
Run Code Online (Sandbox Code Playgroud)
请注意,这些解决方案基于字符串比较,未经优化且无法使用索引。您应该考虑以不同的方式标准化您的表格。(请参阅管理 MySQL 中的分层数据)
关于一些问题:
选择 id 9 的所有子项:
由于该Path列不包含前导斜杠和尾随斜杠,因此您需要将它们连接到路径:
SELECT *
FROM tester
WHERE CONCAT('/', path, '/') LIKE '%/9/%';
Run Code Online (Sandbox Code Playgroud)
选择 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
Run Code Online (Sandbox Code Playgroud)
为简单起见,我使用上面的查询来显示所有级别,如果您想限制 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/%'
Run Code Online (Sandbox Code Playgroud)
我们正在采取的步骤:
LENGTH(p.Path) - LENGTH(REPLACE(p.Path, '/', '')))SUBSTRING_INDEX功能)。