所以在我的情况我有三个表:list,item和list_relation.
每个都item将通过list_id外键链接到列表.
在list_relation看起来像这样:
CREATE TABLE list_relation
(
parent_id INT UNSIGNED NOT NULL,
child_id INT UNSIGNED NOT NULL,
UNIQUE(parent_id, child_id)
FOREIGN KEY (parent_id)
REFERENCES list (id)
ON DELETE CASCADE,
FOREIGN KEY (child_id)
REFERENCES list (id)
ON DELETE CASCADE
);
Run Code Online (Sandbox Code Playgroud)
我希望能够从多个列表继承(包括相关项目).
例如,我有列表:1,2,3.
我想知道是否有任何SQL方法可以防止它成为循环关系.例如
列表1继承自列表3,列表2继承自列表1,列表3继承自列表1.
1 -> 2 -> 3 -> 1
我目前的想法是,我必须首先验证所需的继承,然后将其插入数据库,以确定它是否为循环.
如果您使用MySQL 8.0或MariaDB 10.2(或更高版本),您可以尝试递归CTE(公用表表达式).
假设以下架构和数据:
CREATE TABLE `list_relation` (
`child_id` int unsigned NOT NULL,
`parent_id` int unsigned NOT NULL,
PRIMARY KEY (`child_id`,`parent_id`)
);
insert into list_relation (child_id, parent_id) values
(2,1),
(3,1),
(4,2),
(4,3),
(5,3);
Run Code Online (Sandbox Code Playgroud)
现在,您尝试使用child_id = 1和插入新行parent_id = 4.但这会产生循环关系(1-> 4-> 2-> 1和1-> 4-> 3-> 1),您要阻止它们.要确定是否已存在反向关系,可以使用以下查询,该查询将显示列表4的所有父项(包括继承/传递父项):
set @new_child_id = 1;
set @new_parent_id = 4;
with recursive rcte as (
select *
from list_relation r
where r.child_id = @new_parent_id
union all
select r.*
from rcte
join list_relation r on r.child_id = rcte.parent_id
)
select * from rcte
Run Code Online (Sandbox Code Playgroud)
结果将是:
child_id | parent_id
4 | 2
4 | 3
2 | 1
3 | 1
Run Code Online (Sandbox Code Playgroud)
您可以在结果中看到列表1是列表4的父项之一,并且您不会插入新记录.
由于您只想知道列表1是否在结果中,因此您可以将最后一行更改为
select * from rcte where parent_id = @new_child_id limit 1
Run Code Online (Sandbox Code Playgroud)
或者
select exists (select * from rcte where parent_id = @new_child_id)
Run Code Online (Sandbox Code Playgroud)
顺便说一句:您可以使用相同的查询来防止冗余关系.假设你想用child_id = 4和插入记录parent_id = 1.这将是多余的,因为列表4已经在列表2和列表3上继承了列表1.以下查询将向您显示:
set @new_child_id = 4;
set @new_parent_id = 1;
with recursive rcte as (
select *
from list_relation r
where r.child_id = @new_child_id
union all
select r.*
from rcte
join list_relation r on r.child_id = rcte.parent_id
)
select exists (select * from rcte where parent_id = @new_parent_id)
Run Code Online (Sandbox Code Playgroud)
您可以使用类似的查询来获取所有继承的项目:
set @list = 4;
with recursive rcte (list_id) as (
select @list
union distinct
select r.parent_id
from rcte
join list_relation r on r.child_id = rcte.list_id
)
select distinct i.*
from rcte
join item i on i.list_id = rcte.list_id
Run Code Online (Sandbox Code Playgroud)
小智 1
parent_id在列表中放置一列不是更好吗?
LEFT JOIN然后,您可以通过在列表表上查询 来获取列表树,将parent_id与 匹配list_id,例如:
SELECT t1.list_id, t2.list_id, t3.list_id
FROM list AS t1
LEFT JOIN list as t2 ON t2.parent_id = t1.list_id
LEFT JOIN list as t3 ON t3.parent_id = t2.list_id
WHERE t1.list_id = #your_list_id#
Run Code Online (Sandbox Code Playgroud)
这是您的情况的解决方案吗?不管怎样,我建议你阅读有关在mysql中管理分层数据的内容,你可以找到很多关于这个问题的内容!
| 归档时间: |
|
| 查看次数: |
405 次 |
| 最近记录: |