我在mysql表中有一个基于id
,depth
,parent_id
和path
的树表示。此表中的每个 root 记录的深度为0
,parent_id != null
和path
表示,基于使用0
填充的ID的十六进制值。
树的每个元素都是通过指定depth = parent.depth + 1
,path = parent.path + hex(id)
,parent_id = parent.id
(伪代码)构建的,例如:
id path depth parent_id assigned_user_id
------------------------------------------------------------
1 001 0 NULL NULL
2 002 0 NULL 1
3 001003 1 1 2
4 002004 1 2 1
5 001003005 2 3 2
6 001003005006 3 5 2
7 002004007 2 4 1
8 002004008 2 4 2
9 002004009 2 4 2
10 00200400800A 3 8 2
依旧......
问题是如何将特定用户ID的记录限制为同一分支中的最短路径。例如assigned_user_id = 2
retrive:
id path depth parent_id assigned_user_id
------------------------------------------------------------
3 001003 1 1 2
8 002004008 2 4 2
9 002004009 2 4 2
而不是:
id path depth parent_id assigned_user_id
------------------------------------------------------------
3 001003 1 1 2
5 001003005 2 3 2
6 001003005006 3 5 2
8 002004008 2 4 2
9 002004009 2 4 2
10 00200400800A 3 8 2
答案 0 :(得分:2)
如果我说得对,那么排除parent_id属于所选ID的行可能就足够了。这是因为如果选择了父级和子级,则它们必须位于同一分支中。父母的路径会更短,因此可以排除孩子。
类似的东西:
SELECT *
FROM x
WHERE assigned_user_id = 2
AND parent_id NOT IN (SELECT id FROM x WHERE assigned_user_id = 2)
如果您有这样的树(数字是您指定的用户ID):
A1 G2
/ \ / \
B2 C2 H2 I2
| \ | | \
D2 E2 L1 J2 K2
|
M2
将选择B2,C2,G2和M2。不过,我仍然不确定这是不是你的意图。
答案 1 :(得分:2)
SELECT t1.*
FROM atable t1
LEFT JOIN atable t2
ON t2.assigned_user_id = t1.assigned_user_id AND
t2.path = LEFT(t1.path, CHAR_LENGTH(t2.path)) AND
t2.id <> t1.id
WHERE t1.assigned_user_id = 2
AND t2.id IS NULL
答案 2 :(得分:1)
我会尝试这样的事情:
SELECT * FROM PATHS WHERE ASSIGNED_USER_ID = 2
AND NOT PARENT_ID IN (SELECT ID FROM PATHS WHERE ASSIGNED_USER_ID = 2)
基本上,我们的想法是为给定用户选择顶级父节点。
答案 3 :(得分:1)
背后的理念:如果A以B开头,则B比A短。也许有比“LIKE”更好的东西“以”开头“。
SELECT a.* FROM node AS a
WHERE a.assigned_user_id = ?
AND NOT EXIST
(SELECT * FROM node AS b
WHERE b.assigned_user_id = ?
AND LENGTH(a.path) > LENGTH(b.path)
AND a.path LIKE CONCAT(b.path, '%') )
两者?映射到所需的用户ID。
修改强>
忘记包含assigned_user_id。更改了代码。
第二次编辑
更改代码以避免b = a。
的情况答案 4 :(得分:0)
你尝试过这样的事吗?
select child.assigned_user_id, child.id
from node as child
left join node as parent
on child.path like CONCAT(parent.path, '%')
and child.assigned_user_id = parent.assigned_user_id
and child.id <> parent.id
group by child.assigned_user_id, child.id
having max(parent.id is null) = true
(不确定它是否完全如上所述,但基本上是:在路径上保持连接以提取完整的父项列表,然后以这样的方式聚合,即只保留没有任何父项的节点按assign_user_id分组时。)