Найти количество прямых потомков и распространить их на родителей в иерархической таблице с помощью MySQL 8.0 рекурсивного CTE - PullRequest
1 голос
/ 05 апреля 2020

Я пытаюсь накапливать на каждом узле в иерархии количество прямых потомков. Для узлов, которые не имеют потомков, количество должно быть 0.

В общем, я хочу применять различные типы подсчета / агрегирования в нескольких контекстах, где иерархия точно не определена, как это. Поэтому меня интересует рекурсивное решение.

Рассмотрим следующий код. Как мне «инвертировать» этот запрос таким образом, чтобы вместо вычисления глубины я считал потомков и распространял числа вверх?

create table hierarchy (
    name     varchar(100),
    location varchar(100),
    parent_name varchar(100),
    parent_location varchar(100)
) engine=InnoDB default charset=UTF8MB4;

truncate hierarchy;
insert into hierarchy values
    ('music', '/', NULL, NULL),
    ('classical', '/music', 'music', '/'),
    ('pop', '/music', 'music', '/'),
    ('rock', '/music', 'music', '/'),
    ('bach', '/music/classical', 'classical', '/music');
select * from hierarchy;

with recursive cte as
(
    select name, location, parent_name, parent_location, 1 as depth
    from hierarchy where parent_name is NULL and parent_location is NULL
    union all
    select a.name, a.location, a.parent_name, a.parent_location, depth + 1
    from hierarchy as a inner join cte on a.parent_name = cte.name and a.parent_location = cte.location
)
select *
from cte;

Вывод

name         location           parent_name   parent_location   depth
'music'      '/'                NULL          NULL              1
'classical'  '/music'           'music'       '/'               2
'pop'        '/music'           'music'       '/'               2
'rock'       '/music'           'music'       '/'               2
'bach'       '/music/classical' 'classical'   '/music'          3

Что меня в конечном итоге интересует в это вывод:

name         location           parent_name   parent_location   descendents
'music'      '/'                NULL          NULL              3
'classical'  '/music'           'music'       '/'               1
'pop'        '/music'           'music'       '/'               0
'rock'       '/music'           'music'       '/'               0
'bach'       '/music/classical' 'classical'   '/music'          0

1 Ответ

0 голосов
/ 05 апреля 2020

Вы, похоже, хотите подсчитать количество прямых потомков каждого узла. Если это так, я не думаю, что вам нужен рекурсивный запрос: простой подзапрос должен это сделать:

select 
    h.*,
    (select count(*) from hierarchy h1 where h1.parent_name = h.name) descendants
from hierarchy h

Демонстрация на DB Fiddle :

| name      | location         | parent_name | parent_location | descendants |
| --------- | ---------------- | ----------- | --------------- | ----------- |
| music     | /                |             |                 | 3           |
| classical | /music           | music       | /               | 1           |
| pop       | /music           | music       | /               | 0           |
| rock      | /music           | music       | /               | 0           |
| bach      | /music/classical | classical   | /music          | 0           |
...