好的,让我们再试一次。如果是多对多关系,则不是树或分层数据。
简单地说,具有层次结构的节点在“数据模型”中只能有 2 个连接,它们是父节点和子节点。
对于多对多关系,您可以有 6 个相互关联的用户,这将为您提供类似 6^6 or 46,656 的可能组合(或类似的东西,无论如何它的方式超过 2 个)。
你提到了一些关于关卡的事情,我仍然不知道这是什么。这是权限级别吗?
这些级别不一定会按照您的预期工作(当然我不知道它们是什么),但如果您有一个多对多的关系,那么从逻辑上讲
If user A is related to User B
Than
user B is equally related to User A
假设用户A 是级别1,用户B 是级别2。现在因为A=B 然后B=A。现在你怎么知道要使用哪个级别?
无论如何,多对多关系就像 DB 架构 101,它是基本的。您需要的是一个bridge 表(有时称为junction 表)。所以你有一个users 表然后你有一个users_users 表。
这是我发现的一张图片,显示了这一点,使用学生和班级。这里的想法是一样的,除了我们可以为关系的双方使用users 表。通常将它们命名为table1_table2,所以我们得到users_users。这是一个很好的图像,显示了我想要的,只需将多对多想象为多对一和一对多关系(因为它就是这样)。这有助于解释为什么我们需要额外的表格并且不能仅在一张表格中表示。
在我继续之前检查这个小提琴
https://www.db-fiddle.com/f/6yRBW4jpBJR3MkVpUZP47f/2
这可以这样显示(以基本的方式)
users
id : name
1 : A
2 : B
3 : C
4 : D
5 : E
6 : F
7 : G
8 : H
9 : I
users_users ( brige table )
parent : child
1 : 2
1 : 3
1 : 4
1 : 5
2 : 3
2 : 4
2 : 5
所以用户 1 是 2,3,4,5 的父级,用户 2 是 3,4,5 的父级。需要注意的是,一个用户既可以是另一个用户的父母,也可以是另一个用户的孩子例如:
users_users ( brige table )
parent : child
1 : 2
2 : 1
现在1 是2 的父级,2 是1 的父级,反之亦然。这意味着什么取决于您如何对其进行编码以及您想要对其施加的约定。
密切注意小提琴中的选择查询。注意哪一边是父母,哪一边是孩子。
现在我们可以轻松添加另一个名为 level 的列,请参阅此小提琴 https://www.db-fiddle.com/f/6yRBW4jpBJR3MkVpUZP47f/4
还有我们更新的架构
users
id : name : level
1 : A : 1
2 : B : 2
3 : C : 3
4 : D : 4
5 : E : 5
6 : F : 6
7 : G : 7
8 : H : 8
9 : I : 9
因此,如果我们想找到给定级别的用户,我们就必须决定使用哪个级别。这是因为父级和子级都是用户,然后都为他们分配了一个级别。
我想我们应该使用父母级别。因此,如果我们想查找所有具有一级父级的用户,我们将使用此查询。
SELECT
c.id AS child_id, c.name AS child_name, p.level AS parent_level
FROM
users AS p
JOIN
users_users AS u ON p.id = u.parent
JOIN
users AS c ON c.id = u.child
WHERE
p.level = 1;
这将返回用户2,3,4,5,它们都是用户 1 的子级(即级别 1)。但是每个用户自己的级别与1 不同。如果我们只想要级别 1 的用户。我们只需查询 users 表
SELECT * FROM users WHERE level=1
我们也可以反过来,找到所有有特定级别孩子的父母。为此,我们只需将要查找的列更改为以 p. 为前缀作为父级,然后我们还翻转 WHERE 子句中的条件以使用子 c. 像这样:
SELECT
p.id AS parent_id, p.name AS parent_name, c.level AS child_level
FROM
users AS p
JOIN
users_users AS u ON p.id = u.parent
JOIN
users AS c ON c.id = u.child
WHERE
c.level = 2;
在这里,我将级别切换到 2(1 没有结果),这将返回 User1,这对于子级别 2,3,4 and 5 相同,都将为此返回 1。因为我们有这种关系
users_users ( brige table )
parent : child
1 {lv 1} : 2 {lv 2}
1 {lv 1} : 3 {lv 3}
1 {lv 1} : 4 {lv 4}
1 {lv 1} : 5 {lv 5}
因此,您可以看到,如果我们查找 child.level=2,我们会获得第一个关系,如果我们执行相反的操作 parent.level=1,我们会获得该用户的所有关系。
这似乎更符合你在 cmets 中所说的话,但我仍然不确定我是否完全理解你想要什么。
最后一件非常重要的事情,对于桥牌桌。确保您了解小提琴中用于此的复合主键
CREATE TABLE `users_users` (
`parent` int(10) unsigned NOT NULL,
`child` int(10) unsigned NOT NULL,
PRIMARY KEY (`parent`,`child`) #this is the compound key
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
这里我们将来自双方的用户 ID parent/child 组合为主键。这可以防止关系的重复条目。所以把这个的关键想象成
users_users ( brige table )
parent : child : {key}
1 : 2 : {1~2}
1 : 3 : {1~3}
2 : 1 : {2~1} #<-- this is not a duplicate of {1~2}
#1 : 2 : {1~2} #<-- this key would be a duplicate
# and is not allowed, trying to add this
# will throw a duplicate key error from the DB
我几乎忘记了您的 status 字段,我们可以将其作为简单的 boolean 字段添加到我们的数据库架构中。这将是活动的 1 和非活动的 0。
CREATE TABLE `users` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`name` VARCHAR(30) NOT NULL,
`level` int(10) unsigned NOT NULL,
`status` tinyint(1) NOT NULL DEFAULT '1',
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
然后我们只需在需要时将其添加到WHERE 子句中,非常简单,我相信您可以解决它。 WHERE p.status=1 AND c.level = 2;