문제 설명
Facebook 사용자 간 친구 관계가 edges 테이블에 저장되어 있다.
문제에서는
ID가 3820인 사용자를 포함한 세 명의 사용자가 서로 친구인 경우를 찾아야 한다.
여기서 중요한 점은
단순히
3820 ↔ 100
3820 ↔ 200
만 존재하는 것이 아니라,
3820 ↔ 100
3820 ↔ 200
100 ↔ 200
처럼 세 사람 모두가 서로 친구여야 한다는 것이다.
또한 중복 제거를 위해
user_a_id < user_b_id < user_c_id
를 만족하는 경우만 출력해야 한다.
출력 컬럼
user_a_id
user_b_id
user_c_id
내가 처음 생각한 접근
처음에는
세 명이 친구 관계
↓
셀프 조인인가?
라는 생각이 들었다.
하지만 막상 빈 쿼리창을 보니
어디를 조인해야 하지?
조인 조건은 뭘 써야 하지?
A, B, C는 어떻게 정하지?
가 전혀 떠오르지 않았다.
그래서 처음에는
UNION ALL
+
users 테이블
등을 섞어서 접근하려고 했다.
하지만 문제를 다시 읽어보니
핵심은 사용자가 아니라
친구 관계 자체
를 연결하는 것이었다.
내가 헷갈렸던 부분
1. "세 명이 친구"를 SQL로 어떻게 표현하지?
처음에는
세 명이 친구
라는 말을 보고
막연하게
친구가 3명 이상?
정도로 이해했다.
하지만 실제 문제는
A와 B 친구
A와 C 친구
B와 C 친구
를 모두 만족해야 했다.
즉
A-B
B-C
A-C
관계가 모두 존재해야 한다.
2. JOIN 조건을 어떻게 만들어야 하지?
가장 많이 막혔던 부분.
처음에는
JOIN은 알겠는데
ON 절을 어떻게 써야 하지?
였다.
이 문제를 이해한 결정적인 방법은
A, B, C를 먼저 종이에 적는 것이었다.
A-B
B-C
A-C
그리고 각각 의 위치를
[테이블 ] a , b 라고 할 때, 다음과 같이 관계도가 형성된다.
[ t1 ] A-B
[ t2 ] B-C
[ t3 ] A-C
그러면 자연스럽게
t1의 B
=
t2의 A
가 되어야 연결된다.
그래서
t1.b = t2.a
가 나온다.
또
A-C 관계
를 확인하기 위해
t1의 A
=
t3의 A
t2의 C
=
t3의 C
가 되어야 한다.
그래서
t1.a = t3.a
t2.b = t3.b
가 나온다.
결국 이 문제의 핵심 조건은
t1.b = t2.a
t2.b = t3.b
t1.a = t3.a
였다.
3. JOIN 조건은 어느 ON 절에 써야 할까?
이 부분도 헷갈렸다.
예를 들어
JOIN t2
ON t1.b = t2.a
AND t2.b = t3.b
처럼 쓰고 싶었는데
생각해보면
t3는 아직 등장하지 않았다.
즉
t1
t2
까지만 존재하는 상태에서
t3
를 참조할 수 없다.
그래서
JOIN t3
ON t1.a = t3.a
AND t2.b = t3.b
처럼
해당 테이블이 등장한 이후 ON 절에서 사용해야 한다.
4. UNION과 UNION ALL은 왜 다를까?
친구 수를 세는 문제에서는
UNION ALL
을 사용했었다.
왜냐하면
1 → 2
2 → 1
두 관계가 모두 필요했기 때문이다.
하지만 이번 문제는
친구 관계 존재 여부
가 중요했다.
중복된 관계가 많아지면
같은 삼각형을 여러 번 찾을 수 있다.
그래서
UNION
으로 중복을 제거하였다.
최종 해결 방법
1단계. 친구 관계를 양방향으로 변환
원본 데이터는
1 ↔ 2
형태이다.
이를
1 → 2
2 → 1
형태로 변환한다.
이를 위해
UNION
사용.
2단계. A-B 관계 찾기
3단계. B-C 관계 찾기
t1.b = t2.a
4단계. A-C 관계 존재 여부 확인
t1.a = t3.a
t2.b = t3.b
5단계. 3820 포함 여부 확인
문제 조건에 따라
t1.a = 3820
OR t1.b = 3820
OR t2.b = 3820
를 적용한다.
6단계. 중복 제거
t1.a < t1.b
AND t1.b < t2.b
조건을 통해
A < B < C
를 만족하는 경우만 남긴다.
정답 쿼리
WITH t AS (
SELECT
user_a_id AS a,
user_b_id AS b
FROM edges
UNION
SELECT
user_b_id AS a,
user_a_id AS b
FROM edges
)
SELECT
t1.a AS user_a_id,
t1.b AS user_b_id,
t2.b AS user_c_id
FROM t t1
JOIN t t2
ON t1.b = t2.a
JOIN t t3
ON t1.a = t3.a
AND t2.b = t3.b
WHERE
(
t1.a = 3820
OR t1.b = 3820
OR t2.b = 3820
)
AND t1.a < t1.b
AND t1.b < t2.b;
핵심 SQL 개념 정리
Self Join
이번 문제에서는 같은 테이블을 여러 번 사용했다.
중요한 것은
t1
t2
t3
를
첫 번째 테이블
두 번째 테이블
세 번째 테이블
로 보는 것이 아니라
A-B 관계
B-C 관계
A-C 관계
로 이해하는 것이다.
UNION
이번 문제에서는 친구 관계를 양방향으로 만들기 위해 사용했다.
1 → 2
2 → 1
를 모두 생성한다.
또한 중복 제거를 통해 동일한 관계가 여러 번 생성되는 것을 방지한다.
JOIN 조건 설계
JOIN 조건은 외우는 것이 아니라
먼저 필요한 관계를 그림으로 표현해야 한다.
A-B
B-C
A-C
↓
같은 사람끼리 연결
↓
t1.b = t2.a
t2.b = t3.b
t1.a = t3.a
이번 문제에서 배운 패턴
내 생각
↓
세 명이 친구라는 게 뭘 의미하지?
↓
A-B / B-C / A-C 관계로 분해
↓
각 관계를 t1, t2, t3로 지정
↓
같은 사람끼리 JOIN
↓
3820 포함 여부 필터링
↓
A < B < C 조건으로 중복 제거
↓
정답
한 줄 요약
"세 명이 서로 친구" 문제는 A-B, B-C, A-C 세 관계를 먼저 정의한 뒤, 같은 사람을 기준으로 Self Join하여 연결하는 그래프(네트워크) 문제였다.

문제풀이 완료 !
'TIL' 카테고리의 다른 글
| [TIL170] leetcode - Find COVID Recovery Patients (0) | 2026.06.24 |
|---|---|
| [TIL169] HackerRank - Type of Triangle (0) | 2026.06.24 |
| [TIL167] solvesql - 유량(flow)과 저량(stock) (0) | 2026.06.23 |
| [TIL166] solvesql - Facebook 친구 수 집계하기 (0) | 2026.06.23 |
| [TIL165] solvesql - 세션 유지시간 10분으로 재정의하기(max) (0) | 2026.06.23 |