DataBase

[SolveSQL/Advent of SQL 2024] 세 명이 서로 친구인 관계 찾기

MKJo 2024. 12. 26. 13:06

문제:

https://solvesql.com/problems/friend-group-of-3/

 

 

처음엔 간단(?)해 보였지만 하면 할수록 점점 이상한 결과들이 나오기 시작했다.. 

셀프 조인을 2~3번씩 걸면서 조건을 이렇게 저렇게 주고 해봤는데 원하는 결과가 나오지않아서 결국 야매스러운 방법으로 해결했다..

 

 

 

 

 

1. Edges 테이블의 USER_A_ID 혹은 USER_B_ID가 3820인 행찾기

 

 

 

2. 3820의 친구목록을 하나의 컬럼으로 묶어주기

WITH UserFriends AS (
SELECT 
      CASE WHEN User_A_Id = 3820 THEN USER_B_ID 
           ELSE User_A_Id
      END as Friend
FROM Edges 
WHERE 3820 IN (user_a_id, user_b_id)
)

 

 

 

3. [3820의 친구목록] 중 Edges테이블의 [user_a_id, user_b_id] 두 컬럼 모두에 해당하는 행을 찾은 후 작은수, 큰수로 정렬하여 중복제거 [1, 2], [2, 1]과 같은 조합이 있을 수 있으므로..

 ex) 3820의 친구목록이 1,2,3,4 라면 Edges 테이블의 [user_a_id, user_b_id] 조합이 [1,2,3,4]에서 조합되는 녀석

 

FriendPairs AS (
    SELECT DISTINCT
        CASE 
            WHEN E.user_a_id < E.user_b_id THEN E.user_a_id 
            ELSE E.user_b_id 
        END as user_a_id,
        CASE 
            WHEN E.user_a_id < E.user_b_id THEN E.user_b_id 
            ELSE E.user_a_id 
        END as user_b_id
    FROM Edges E
    INNER JOIN UserFriends UF1 ON E.user_a_id = UF1.Friend
    INNER JOIN UserFriends UF2 ON E.user_b_id = UF2.Friend
)

 

 

풀고나서 알았는데 Edges컬럼의 user_a_id < user_b_id는 항상 참이다. 즉 위의 CASE구문없이 user_a_id, user_b_id만 조회 했어도 됐음

 

 

 

 

 

 

중간결과

 

 

이제 위  user_a_id, user_b_id 사이에 A < B < C 순으로 3820을 끼워넣으면 된다.

어떻게할까 고민좀 하긴 했는데.. 그냥 무식하게 CASE로 때려박았다..

 

 

 

4. 최종결과

 

WITH UserFriends AS (
    -- 3820 유저의 모든 친구
    SELECT 
      CASE WHEN User_A_Id = 3820 THEN USER_B_ID 
           ELSE User_A_Id
      END as Friend
    FROM Edges 
    WHERE 
      3820 IN (user_a_id, user_b_id)
),
FriendPairs AS (
    -- 3820 유저의 친구들 쌍
    SELECT DISTINCT
        CASE 
            WHEN E.user_a_id < E.user_b_id THEN E.user_a_id 
            ELSE E.user_b_id 
        END as user_a_id,
        CASE 
            WHEN E.user_a_id < E.user_b_id THEN E.user_b_id 
            ELSE E.user_a_id 
        END as user_b_id
    FROM Edges E
    INNER JOIN UserFriends UF1 ON E.user_a_id = UF1.Friend
    INNER JOIN UserFriends UF2 ON E.user_b_id = UF2.Friend
)
SELECT 

  CASE WHEN USER_A_ID < 3820 AND USER_B_ID < 3820 THEN USER_A_ID -- [3820]이 가장 큰 경우
       WHEN USER_A_ID < 3820                      THEN USER_A_ID -- [3820]이 중간인 경우
       ELSE                                            3820      -- [3820]이 가장 작은 경우
  END as user_a_id,

  CASE WHEN USER_A_ID < 3820 AND USER_B_ID < 3820 THEN USER_B_ID
       WHEN USER_A_ID < 3820                      THEN 3820
       ELSE                                            USER_A_ID
  END as user_b_id,

  CASE WHEN USER_A_ID < 3820 AND USER_B_ID < 3820 THEN 3820
       WHEN USER_A_ID < 3820                      THEN USER_B_ID
       ELSE                                            USER_B_ID
  END as user_c_id

FROM
  FriendPairs

 

 

참으로 무식한 결과다.. ㅎㅎ

하지만 통과^^