Member 4529316 Ответов: 2

Рекурсивное чтение таблицы со связанным списком


У меня есть стол на котором стоит дерево друзей;
FID-это идентификатор друга, а MId-это тот, кто пригласил этого друга присоединиться.

Я хотел бы запросить таблицу, чтобы получить все вложенные друзья, к которым первоначальный триггер для присоединения был сделан в середине 3 (например)

Например таблица:

FID     MID     Vflag
1   9   t         
2   9   t         
3   9   t         
4   9   f         
5   9   f         
6   9   t         
7   5   t         
8   3   t         
9   3   t         
10  3   t         
11  3   t         
12  4   t         
15  10  t         
16  10  t         
17  10  t         
18  15  t         
19  15  t         
20  15  t


Что я уже пробовал:

WITH Ancestors(InvitedBy, Child) AS

(

	SELECT InvitedBy, FriendID as Child

	FROM PromotionPlan WHERE FriendID IS NOT NULL
	   
	UNION ALL
	   
	SELECT b.InvitedBy, a.FriendID as Child FROM 

	PromotionPlan a, Ancestors b

	WHERE b.Child = a.InvitedBy

)

SELECT a.* FROM PromotionPlan a WHERE InvitedBy IN (SELECT InvitedBy FROM Ancestors WHERE Child=3)

Maciej Los

Примерные данные не соответствуют запросу.

Member 4529316

Я написал названия столбцов коротко, Fid - FriendID, MID - InvitedBy,vFlag(то же самое)

Maciej Los

Ладно, извини.

Maciej Los

Когда я смотрю на ваши данные, я немного смущен... Похоже, ваши данные неверны. Почему?
FriendID=3 был приглашен 9, а FriendID=9 был приглашен 3. Таким образом, это приводит к тому, что cte переходит в бесконечный цикл:
3->9->9->3->3->9..... и так далее...

Member 4529316

ой, хороший улов этого не заметил

Maciej Los

;)

2 Ответов

Рейтинг:
8

Member 4529316

-- Change you answer slightly so it will give me the opposite 
-- having friends tree
;WITH Ancestors AS
(
	--initial part
	SELECT 0 AS Distance, InvitedBy, FriendID , CONVERT(varchar(MAX),  CAST(InvitedBy AS VARCHAR(10))+ '<-' + CAST(FriendID AS VARCHAR(10))) AS Relation
	FROM PromotionPlan
	WHERE InvitedBy =3
	UNION ALL
	SELECT Distance + 1,  b.InvitedBy,b.FriendID,Relation + '<-' + CAST(b.FriendID AS VARCHAR(10))
	FROM Ancestors a INNER JOIN  PromotionPlan b ON a.FriendID = b.InvitedBy
	WHERE NOT b.FriendID IS NULL
)
SELECT  *
FROM Ancestors order by Distance


Результаты:
Distance	InvitedBy	FriendID	Relation
0	3	8	3<-8
0	3	10	3<-10
0	3	11	3<-11
1	11	16	3<-11<-16
1	10	15	3<-10<-15
1	10	17	3<-10<-17
2	15	18	3<-10<-15<-18
2	15	19	3<-10<-15<-19
2	15	20	3<-10<-15<-20
2	16	21	3<-11<-16<-21


Maciej Los

Есть 5!

Рейтинг:
13

Maciej Los

Пожалуйста, сначала прочтите мой комментарий о бесконечном цикле.

С небольшими изменениями в ваших данных...

DECLARE @PromotionPlan TABLE(FriendID int, InvitedBy int, Vflag VARCHAR(1))

INSERT INTO @PromotionPlan(FriendID, InvitedBy, Vflag)
VALUES(1, NULL, 't'), (2, 1, 't'), (3, 2, 't'),
(4, 9, 'f'), (5, 9, 'f'), (6, 9, 't'),
(7, 5, 't'), (8, 3, 't'), (9, 3, 't'),
(10, 3, 't'), (11, 3, 't'), (12, 4, 't'),
(15, 10, 't'), (16, 10, 't'), (17, 10, 't'),
(18, 15, 't'), (19, 15, 't'), (20, 15, 't')

;WITH Ancestors AS
(
	--initial part
	SELECT 0 AS Distance, FriendID , InvitedBy, CONVERT(varchar(MAX), CAST(FriendID AS VARCHAR(10))+ '<-' + CAST(InvitedBy AS VARCHAR(10))) AS Relation
	FROM @PromotionPlan
	WHERE FriendID =20
	UNION ALL
	SELECT Distance + 1, b.FriendID, b.InvitedBy, Relation + '<-' + CAST(b.InvitedBy AS VARCHAR(10))
	FROM Ancestors a INNER JOIN  @PromotionPlan b ON a.InvitedBy = b.FriendID
	WHERE NOT b.InvitedBy IS NULL
)
SELECT  *
FROM Ancestors


Результат:
Distance	FriendID	InvitedBy	Relation
0	20	15	20<-15
1	15	10	20<-15<-10
2	10	3	20<-15<-10<-3
3	3	2	20<-15<-10<-3<-2
4	2	1	20<-15<-10<-3<-2<-1