MySql 递归 - 从给定的 id 获取所有 children 和 parents
MySql Recursive - get all children and parents from a given id
MySQL 版本 8.0
架构 SQL
CREATE TABLE IF NOT EXISTS `department` (
`id` INT NOT NULL,
`name` VARCHAR(45) NOT NULL,
`father` INT NULL,
PRIMARY KEY (`id`),
INDEX `fk_department_department_idx` (`father` ASC) VISIBLE,
CONSTRAINT `fk_department_department`
FOREIGN KEY (`father`)
REFERENCES `department` (`id`)
ON DELETE NO ACTION
ON UPDATE NO ACTION)
ENGINE = InnoDB;
insert into department (id,name,father)
values
(1, 'dp1',null),
(2, 'dp2',null),
(3, 'dp3',1),
(4, 'dp4',1),
(5, 'dp5',2),
(6, 'dp6',4),
(7, 'dp7',6),
(8, 'dp8',6),
(9, 'dp9',6);
SET GLOBAL sql_mode=(SELECT REPLACE(@@sql_mode,'ONLY_FULL_GROUP_BY',''));
SET SESSION sql_mode = '';
我的查询:
WITH RECURSIVE cte_department AS (
SELECT
d1.id,
d1.name,
d1.father
FROM
department d1
WHERE
d1.id=6
UNION ALL
SELECT
d2.id,
d2.name,
d2.father
FROM
department d2
INNER JOIN cte_department cte ON cte.id = d2.father
)
SELECT * FROM cte_department;
结果:
id name father
6 dp6 4
7 dp7 6
8 dp8 6
9 dp9 6
我需要的:
id name father
1 dp1 null
4 dp4 1
6 dp6 4
7 dp7 6
8 dp8 6
9 dp9 6
问题是:
我可以获得所有子项,但我需要将给定 ID 中的所有 parents 添加到此查询中,在本例中为 ID 6。
我坚持这一点。如果有人可以帮助我,请关注 fiddle.
递归部分可以有多个查询块。
WITH RECURSIVE cte_department AS (
SELECT
d1.id,
d1.name,
d1.father,
'Begin' state
FROM
department d1
WHERE
d1.id=6
UNION ALL
SELECT
d2.id,
d2.name,
d2.father,
'Up'
FROM
department d2
INNER JOIN
cte_department cte
ON
cte.father = d2.id
WHERE
cte.state in ('Begin', 'Up')
UNION ALL
SELECT
d2.id,
d2.name,
d2.father,
'Down'
FROM
department d2
INNER JOIN
cte_department cte
ON
cte.id = d2.father
WHERE
cte.state in ('Begin', 'Down')
)
SELECT
id, name, father
FROM
cte_department
ORDER BY
father, id, name;
在 db<>fiddle 上试用。
我会使用两个单独的递归查询:一个用于获取 children,另一个用于 parents,然后是 union
结果。您可以跟踪每个节点的级别,以便在结果集中对记录进行正确排序:
with recursive
children as (
select 1 as lvl, d.* from department d where id = 6
union all
select c.lvl, d.* from department d inner join children c on c.id = d.father
),
parents as (
select 1 as lvl, d.* from department d where id = 6
union all
select p.lvl - 1, d.* from department d inner join parents p on d.id = p.father
)
select * from parents
union -- on purpose, to remove the duplicate on id 6
select * from children
order by lvl;
这比在同一个查询中有多个 union all
成员更安全。 MySQL 不保证递归中成员的求值顺序,因此使用此技术可能会导致意外行为。
与你的问题无关,但是:在你的代码中可以看到以下内容:
SET GLOBAL sql_mode=(SELECT REPLACE(@@sql_mode,'ONLY_FULL_GROUP_BY',''));
SET SESSION sql_mode = '';
只是不要。 ONLY_FULL_GROUP_BY
有一个很好的理由,那就是让 MySQL 在聚合查询方面与 SQL 标准一致。禁用此 SQL 模式绝不是一个好主意。
MySQL 版本 8.0 架构 SQL
CREATE TABLE IF NOT EXISTS `department` (
`id` INT NOT NULL,
`name` VARCHAR(45) NOT NULL,
`father` INT NULL,
PRIMARY KEY (`id`),
INDEX `fk_department_department_idx` (`father` ASC) VISIBLE,
CONSTRAINT `fk_department_department`
FOREIGN KEY (`father`)
REFERENCES `department` (`id`)
ON DELETE NO ACTION
ON UPDATE NO ACTION)
ENGINE = InnoDB;
insert into department (id,name,father)
values
(1, 'dp1',null),
(2, 'dp2',null),
(3, 'dp3',1),
(4, 'dp4',1),
(5, 'dp5',2),
(6, 'dp6',4),
(7, 'dp7',6),
(8, 'dp8',6),
(9, 'dp9',6);
SET GLOBAL sql_mode=(SELECT REPLACE(@@sql_mode,'ONLY_FULL_GROUP_BY',''));
SET SESSION sql_mode = '';
我的查询:
WITH RECURSIVE cte_department AS (
SELECT
d1.id,
d1.name,
d1.father
FROM
department d1
WHERE
d1.id=6
UNION ALL
SELECT
d2.id,
d2.name,
d2.father
FROM
department d2
INNER JOIN cte_department cte ON cte.id = d2.father
)
SELECT * FROM cte_department;
结果:
id name father
6 dp6 4
7 dp7 6
8 dp8 6
9 dp9 6
我需要的:
id name father
1 dp1 null
4 dp4 1
6 dp6 4
7 dp7 6
8 dp8 6
9 dp9 6
问题是: 我可以获得所有子项,但我需要将给定 ID 中的所有 parents 添加到此查询中,在本例中为 ID 6。 我坚持这一点。如果有人可以帮助我,请关注 fiddle.
递归部分可以有多个查询块。
WITH RECURSIVE cte_department AS (
SELECT
d1.id,
d1.name,
d1.father,
'Begin' state
FROM
department d1
WHERE
d1.id=6
UNION ALL
SELECT
d2.id,
d2.name,
d2.father,
'Up'
FROM
department d2
INNER JOIN
cte_department cte
ON
cte.father = d2.id
WHERE
cte.state in ('Begin', 'Up')
UNION ALL
SELECT
d2.id,
d2.name,
d2.father,
'Down'
FROM
department d2
INNER JOIN
cte_department cte
ON
cte.id = d2.father
WHERE
cte.state in ('Begin', 'Down')
)
SELECT
id, name, father
FROM
cte_department
ORDER BY
father, id, name;
在 db<>fiddle 上试用。
我会使用两个单独的递归查询:一个用于获取 children,另一个用于 parents,然后是 union
结果。您可以跟踪每个节点的级别,以便在结果集中对记录进行正确排序:
with recursive
children as (
select 1 as lvl, d.* from department d where id = 6
union all
select c.lvl, d.* from department d inner join children c on c.id = d.father
),
parents as (
select 1 as lvl, d.* from department d where id = 6
union all
select p.lvl - 1, d.* from department d inner join parents p on d.id = p.father
)
select * from parents
union -- on purpose, to remove the duplicate on id 6
select * from children
order by lvl;
这比在同一个查询中有多个 union all
成员更安全。 MySQL 不保证递归中成员的求值顺序,因此使用此技术可能会导致意外行为。
与你的问题无关,但是:在你的代码中可以看到以下内容:
SET GLOBAL sql_mode=(SELECT REPLACE(@@sql_mode,'ONLY_FULL_GROUP_BY',''));
SET SESSION sql_mode = '';
只是不要。 ONLY_FULL_GROUP_BY
有一个很好的理由,那就是让 MySQL 在聚合查询方面与 SQL 标准一致。禁用此 SQL 模式绝不是一个好主意。