Добро пожаловать в форум, Guest  >>   Войти | Регистрация | Поиск | Правила | В избранное | Подписаться
Все форумы / Microsoft SQL Server Новый топик    Ответить
 Собрать дерево вхождений  [new]
Gamlex
Member

Откуда:
Сообщений: 18
Добрый день.

В базе данных на MS SQL есть таблица, смысл которой показать вхождения одних компонентов в другие. К примеру:

Id IdIn
1 2
1 3
2 4
3 5
5 8
5 19
...

Столбец Id - Id компонента, IdIn показывает какие компоненты входят в компонент Id

В программе нужно построить дерево вхождений где верхушкой является определённый компонент. Например, 1й компонент раскрывается на 2 и 3, во втором видим 4, в третьем 5.

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

Учитывая, что таких вхождений может быть до 400, а подключение к базе происходит через интернет, возможны большие задержки в формировании.

ВОПРОС: По сути мне нужны все ID которые напрямую или через другие компоненты входят в компонент с нужным ID. Можно ли как то это реализовать с помощью хранимой процедуры, функции, или может быть это можно сделать единым запросом? Много думал как это сделать, но к сожалению безуспешно. Прошу помочь.
12 сен 19, 22:51    [21969926]     Ответить | Цитировать Сообщить модератору
 Re: Собрать дерево вхождений  [new]
invm
Member

Откуда: Москва
Сообщений: 9128
https://www.google.ru/search?q=ms sql рекурсивные запросы
12 сен 19, 23:00    [21969935]     Ответить | Цитировать Сообщить модератору
 Re: Собрать дерево вхождений  [new]
uaggster
Member

Откуда:
Сообщений: 770
Если у вас - заведомое дерево, то можно обойтись рекурсивным запросом, как выше указал Akina.
Однако, если у вас в цепочке есть петли (например, это может быть ошибкой бизнес-логики), то одним запросом - не получится.
Если только у вас не 2019 и вы не храните всё это в виде графа.
13 сен 19, 08:54    [21970034]     Ответить | Цитировать Сообщить модератору
 Re: Собрать дерево вхождений  [new]
uaggster
Member

Откуда:
Сообщений: 770
invm, конечно же, прошу прощения.
13 сен 19, 08:55    [21970035]     Ответить | Цитировать Сообщить модератору
 Re: Собрать дерево вхождений  [new]
Minamoto
Member

Откуда: Москва
Сообщений: 1162
uaggster
Однако, если у вас в цепочке есть петли (например, это может быть ошибкой бизнес-логики), то одним запросом - не получится.
Получится.
13 сен 19, 09:51    [21970104]     Ответить | Цитировать Сообщить модератору
 Re: Собрать дерево вхождений  [new]
Akina
Member

Откуда: Зеленоград, Москва, Россия
Сообщений: 20223
uaggster
если у вас в цепочке есть петли (например, это может быть ошибкой бизнес-логики), то одним запросом - не получится
Ему нужны не полные пути, а голый список, в этом случае рекурсия в CTE нормально завершится после выбора всех узлов. Просто нужно в рекурсивной части отсекать то, что уже есть.
13 сен 19, 09:53    [21970108]     Ответить | Цитировать Сообщить модератору
 Re: Собрать дерево вхождений  [new]
uaggster
Member

Откуда:
Сообщений: 770
Minamoto
uaggster
Однако, если у вас в цепочке есть петли (например, это может быть ошибкой бизнес-логики), то одним запросом - не получится.
Получится.

А как?
Например:
Create table #t (id_parent int not null, id_child int not null, primary key clustered (id_parent, id_child))

insert into #t (id_parent, id_child)
values
(1, 2),
(2, 2),
(2, 3),
(2, 4),
(4, 3),
(3, 1),
(5, 5),
(5, 6),
(5, 7),
(7, 5),
(8, 8)

Должно получиться:
1, 2, 3, 4
5, 6, 7
8
13 сен 19, 13:23    [21970288]     Ответить | Цитировать Сообщить модератору
 Re: Собрать дерево вхождений  [new]
Minamoto
Member

Откуда: Москва
Сообщений: 1162
uaggster
Должно получиться:
1, 2, 3, 4
5, 6, 7
8

Не, в постановке автора
Gamlex
В программе нужно построить дерево вхождений где верхушкой является определённый компонент.


uaggster
Minamoto
пропущено...
Получится.

А как?


WITH cte AS
(
    SELECT id_parent,
           id_child, 
           CAST('/' + CAST(id_parent AS varchar(max)) + '/' AS varchar(MAX)) AS path
    FROM #t
    WHERE id_parent = 1
    UNION ALL
    SELECT t.id_parent, 
           t.id_child, 
           CAST(cte.path + CAST(t.id_parent AS varchar(MAX)) + '/' AS varchar(max))
    FROM   cte
            INNER JOIN #t t ON cte.id_child = t.id_parent
    WHERE   cte.path NOT LIKE '%/' + CAST(t.id_parent AS varchar(MAX)) + '/%'
)
SELECT id_parent, cte.id_child
FROM cte
13 сен 19, 13:59    [21970344]     Ответить | Цитировать Сообщить модератору
 Re: Собрать дерево вхождений  [new]
uaggster
Member

Откуда:
Сообщений: 770
Minamoto, а, понятно.
Это я - вылил воду из чайника и попытался свести задачу к предыдущей.
:-)
13 сен 19, 14:55    [21970435]     Ответить | Цитировать Сообщить модератору
 Re: Собрать дерево вхождений  [new]
Gamlex
Member

Откуда:
Сообщений: 18
Большое спасибо за ответы! Буду разбираться.
13 сен 19, 15:57    [21970506]     Ответить | Цитировать Сообщить модератору
Все форумы / Microsoft SQL Server Ответить