SQL中的传递属性

时间:2014-11-26 19:55:40

标签: mysql sql

这是一个我觉得应该知道的问题,但是我一直有一个像我想要的那样富有表现力的时间。

我的问题很简单:在SQL中表达传递关系的习惯是什么?一个具体的例子:

说我有以下架构:

user(email, name)
friends(friend1_email, friend2_email)

我在表达以下问题时遇到问题:

查找用户A,B和C,以便A是B的朋友,B是C的朋友,但C不是A的朋友。

我承认这是家庭作业,但我一直有表达查询的概念问题。任何援助将不胜感激。感谢。

2 个答案:

答案 0 :(得分:2)

我对复杂查询的建议总是从简单开始:

# Find friends A and B
select A.email as A_email, A.name as A_name, B.email as B_email, B.name as B_name
from user A
join friends
on A.email = friends.friend1_email
join user B
on B.email = friends.friend2.email

很简单,让我们再为B和C做一遍:

# Find friends B and C
select B.email as B_email, B.name as B_name, C.email as C_email, C.name as C_name
from user B
join friends
on B.email = friends.friend1_email
join user C
on C.email = friends.friend2.email

现在,让我们结合在一个查询中获取A,B和C

# Find friends A, B, and C
select A.email as A_email, A.name as A_name, B.email as B_email, B.name as B_name, C.email as C_email, C.name as C_name
from user A
join friends f1
on A.email = f1.friend1_email
join user B
on f1.friend2_email = B.email
join friends f2
on B.email = f2.friend1_email
join user C
on f2.friend2_email = C.email

上述查询将向我们提供所有用户A,他们是用户B的朋友,他们是用户C的朋友,但不会将结果集限制为A和C不是朋友的记录。要获得该结果集,我们必须稍微修改一下我们的查询。

# Find friends A, B, and C
select A.email as A_email, A.name as A_name, B.email as B_email, B.name as B_name, C.email as C_email, C.name as C_name
from user A
join friends f1
on A.email = f1.friend1_email
join user B
on f1.friend2_email = B.email
join friends f2
on B.email = f2.friend1_email
join user C
on f2.friend2_email = C.email
left join friends f3
on A.email = f3.friend1_email
and C.email = f3.friend2_email
where
    f3.friend1_email is null

答案 1 :(得分:0)

类似的东西:

select *
from friends a

--If this joins, a and b are friends
left join friends b
on (a.friend1_email = b.friend1_email or
    a.friend1_email = b.friend2_email or
    a.friend2_email = b.friend1_email or
    a.friend2_email = b.friend2_email)

--If this joins, b and c are friends
left join friends c
on (b.friend1_email = c.friend1_email or
    b.friend1_email = c.friend2_email or
    b.friend2_email = c.friend1_email or
    b.friend2_email = c.friend2_email)

--If this joins, c and a are friends.
--Also making sure that a is same person as a2
left join friends a2
on (c.friend1_email = a2.friend1_email or
    c.friend1_email = a2.friend2_email or
    c.friend2_email = a2.friend1_email or
    c.friend2_email = a2.friend2_email)
and (a.friend1_email = a2.friend1_email or
     a.friend1_email = a2.friend2_email or
     a.friend2_email = a2.friend1_email or
     a.friend2_email = a2.friend2_email)

where b.friend1_email is not null --join was made, a and b are friends
and c.friend1_email is not null --join was made, b and c are friends
and a2.friend1_email is null --join was NOT made, a and c are NOT friends