2014-11-26 2 views
3

이것은 내가 알아야 할 질문이지만, 나는 SQL에서 표현하고자하는 것처럼 지루한 시간을 보냈다.SQL의 전이 속성

제 질문은 단순한 질문입니다. SQL에서 전이 관계를 표현하기위한 관용구는 무엇입니까? 구체적인 예 :

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

나는 다음과 같은 쿼리 표현에 문제가있어 :

찾기 사용자 A, B 및 C 등은 A가 친구임을를

나는 다음과 같은 스키마를 말해봐 B와 B는 C와 친구지만 C는 A와 친구가 아닙니다.

나는 이것이 숙제라고 인정 하겠지만, 나는 표현을 표현하는 데 개념적인 문제가있었습니다. 어떤 도움을 주시면 감사하겠습니다. 감사.

+2

방향 그래프를 탐색하려합니까? 그렇다면 순전히 순수한 SQL로 처리하기가 어려울 것입니다. 프로세스가 종종 재귀 적으로 반복적이기 때문입니다. – tadman

+2

@tadman : 10 년 이상 재귀 쿼리가 SQL 표준에 있었기 때문에 깊이 재귀는 SQL과 관련하여 문제가되지 않습니다. MySQL만이 아직 그것을 할 수 없다. –

+0

@a_horse_with_no_name SQL * 표준이 이러한 일을 허용하지만 이것은 MySQL입니다. – tadman

답변

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 

위의 쿼리는 사용자 C와 친구 인 사용자 B와 친구 인 모든 사용자 A를 제공하지만 결과 세트를 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 
+0

우정이 대칭 적이 지 않으면이 솔루션이 작동하지 않는다고 말하는 것이 잘못 되었습니까? 즉, 사용자 A가 B와 친구이지만 사용자 B가 A와 친구가 아니 었습니까? –

+0

제가 제공 한 해결책은 우정이 상호적이고 방향이없는 것으로 가정합니다. 즉, A와 B는 친구입니다. B는 B가 A와 친구라고 암시합니다. 그렇지 않으면 쿼리를 다음과 같이 수정해야합니다. 그걸 설명해. –

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