Как создать нерекурсивный MySQL рекурсивный запрос - PullRequest
0 голосов
/ 30 марта 2020

Здесь есть связанный вопрос: SO - Mysql Рекурсивный запрос

Я пытаюсь определить, как создать рекурсивный запрос в mysql (версия> = 8) который может собрать все строки, которые каким-то образом «связаны» с исходной строкой. Структура относительно проста:

CREATE TABLE link (
  id INT,
  left_id INT,
  right_id INT
);

CREATE TABLE item (
  id INT,
  content VARCHAR(100)
);

INSERT INTO item (id, content) VALUES (1, 'first linked item');
INSERT INTO item (id, content) VALUES (2, 'unlinked item');
INSERT INTO item (id, content) VALUES (3, 'second linked item');
INSERT INTO item (id, content) VALUES (4, 'third linked item');
INSERT INTO item (id, content) VALUES (5, 'fourth linked item');
INSERT INTO item (id, content) VALUES (6, 'second group item 1');
INSERT INTO item (id, content) VALUES (7, 'second group item 2');

INSERT INTO link (id, left_id, right_id) VALUES (1, 1, 3);
INSERT INTO link (id, left_id, right_id) VALUES (2, 4, 3);
INSERT INTO link (id, left_id, right_id) VALUES (2, 5, 1);
INSERT INTO link (id, left_id, right_id) VALUES (4, 6, 7);

Здесь мы делаем ряд строк "item". Позже мы можем решить произвольно связать один элемент с другим, добавив строку в таблицу «link». «left_id» и «right_id» - это просто идентификатор одного элемента и другого элемента. Это не означает, что ссылка сделана с одним элементом слева или справа.

Запрос должен начинаться с указанного элемента или элементов, находить ссылки с совпадающими left_id или right_id и добавлять элементы к результатам, затем для этих новых строк проверять наличие дополнительных ссылок и т. Д. c, пока не появятся никого не осталось

Для тестовых данных, представленных выше, я ожидал бы:

Calling query with condition "content = 'first linked item'":
Result: 
1 | 'first linked item'
3 | 'second linked item'
4 | 'third linked item'
5 | 'fourth linked item'
Calling query with condition "content = 'second group item 2'":
Result:
6 | 'second group item 1'
7 | 'second group item 2'

Какие средства существуют в mysql 8+ для эффективного вызова таких запросов?

1 Ответ

1 голос
/ 30 марта 2020

Вы можете пройтись по графику с помощью рекурсивного CTE. Например:

with
recursive i as (
  select id, content, -1 as source 
  from item where content = 'first linked item'
 union all
  select m.id, m.content, i.id
  from i
  join link l on l.left_id = i.id or l.right_id = i.id
  join item m on m.id <> i.id and m.id <> i.source and m.id = l.left_id
              or m.id <> i.id and m.id <> i.source and m.id = l.right_id
)
select id, content from i;

Затем просто измените условие поиска в строке 3, чтобы начать с другого элемента.

Это решение будет работать хорошо, если график не работает. иметь циклы.

РЕДАКТИРОВАТЬ: Решение, которое имеет дело с циклами

По запросу, вот решение, которое хорошо работает с циклами:

with
recursive i as (
  select id, content, concat(',', id, ',') as route 
  from item where content = 'first linked item'
 union all
  select m.id, m.content, concat(i.route, m.id, ',')
  from i
  join link l on l.left_id = i.id or l.right_id = i.id
  join item m on i.route not like concat('%,', m.id, ',%')
    and (m.id = l.left_id or m.id = l.right_id)
)
select distinct id, content from i;

См. DB Fiddle , где я ввел цикл.

...