我在 SQL 中有下表:
CREATE TABLE friendships
(
id INT PRIMARY KEY,
person VARCHAR(50),
friend VARCHAR(50)
);
INSERT INTO friendships (id, person, friend) VALUES
(1, 'person3', 'person9'),
(3, 'person10', 'person4'),
(4, 'person2', 'person1'),
(5, 'person6', 'person7'),
(7, 'person4', 'person10'),
(8, 'person6', 'person7'),
(10, 'person10', 'person9'),
(11, 'person5', 'person10'),
(12, 'person3', 'person7'),
(13, 'person9', 'person5'),
(14, 'person9', 'person7'),
(15, 'person9', 'person5'),
(16, 'person3', 'person6'),
(17, 'person8', 'person9'),
(18, 'person10', 'person2'),
(19, 'person7', 'person5'),
(20, 'person10', 'person8');
使用 R,我可以绘制表格数据,如下所示:
library(igraph)
friendships = structure(list(person = c("person3", "person10", "person2", "person6",
"person4", "person6", "person10", "person5", "person3", "person9",
"person9", "person9", "person3", "person8", "person10", "person7",
"person10"), friend = c("person9", "person4", "person1", "person7",
"person10", "person7", "person9", "person10", "person7", "person5",
"person7", "person5", "person6", "person9", "person2", "person5",
"person8")), row.names = c(1L, 3L, 4L, 5L, 7L, 8L, 10L, 11L,
12L, 13L, 14L, 15L, 16L, 17L, 18L, 19L, 20L), class = "data.frame")
g <- graph_from_data_frame(df, directed = FALSE)
plot(g, vertex.size=10, vertex.label.cex=0.8)
仅使用SQL命令,我想回答以下问题(将来,泛化到n级):
我不确定如何在 SQL 中执行这些操作 - 我通常使用 igraph 来解决这些问题。
这是我尝试回答第一个问题:
SELECT COUNT(DISTINCT f2.friend)
FROM friendships f1
JOIN friendships f2 ON f1.friend = f2.person
WHERE f1.person = 'person10' AND f2.friend != 'person10' AND f2.friend NOT IN (
SELECT friend FROM friendships WHERE person = 'person10'
);
#result
3
这是我尝试回答第二个问题:
SELECT DISTINCT f2.friend
FROM friendships f1
JOIN friendships f2 ON f1.friend = f2.person
WHERE f1.person = 'person10' AND f2.friend != 'person10' AND f2.friend NOT IN (
SELECT friend FROM friendships WHERE person = 'person10'
);
#result
1 person5
2 person7
3 person1
然而,这些并不是正确的结果。
有人可以告诉我如何正确执行此操作吗?
谢谢!
考虑这个递归示例
with t0 as (
select person,friend
from friendships
-- where person='person10'
union
select friend,person
from friendships
-- where friend='person10'
)
, r as(
select person,friend,1 lvl
,cast(concat(person,'-',friend) as varchar(1000))path
from t0
union all
select r.person,t.friend ,r.lvl+1 lvl
,cast(concat(path,'-',t.friend) as varchar(1000)) path
from r
inner join friendships t on (t.person=r.friend and t.friend<>r.person)
where lvl<2
union all
select r.person,t.person ,r.lvl+1 lvl
,cast(concat(path,'-',t.person) as varchar(1000))path
from r
inner join friendships t on (t.friend=r.friend and t.person<>r.person)
where lvl<2
)
,allfriends as (
select person,friend ,count(*) qty
from r
group by person,friend
)
-- select * from r order by lvl,friend;
-- select * from allfriends;
select person,count(*)friend_qty
from allfriends
group by person