根据mysql中的路径选择

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;会工作得很好。


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

所以我想最终得到一行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)


**选择9的孩子的id向下到x级别,级别相对于9,

因此,在这个例子中,我们将再次使用 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)

The*_*ter 3

请注意,这些解决方案基于字符串比较,未经优化且无法使用索引。您应该考虑以不同的方式标准化您的表格。(请参阅管理 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)

我们正在采取的步骤:

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