DA Study/TIL

[TIL] UNION과 UNION ALL의 차이 #SQL #SQLite #solvesql

harrym8n 2025. 2. 21. 17:58

solvesql - 친구 수 집계하기
👉 문제 바로가기(solvesql)

-- 데이터베이스에 포함된 모든 사용자에 대해 각 사용자의 친구 수를 집계해 출력

WITH tmp_t AS (
  SELECT
    user_id,
    SUM(num_friends) as num_friends
  FROM
    (SELECT user_a_id as user_id, COUNT(DISTINCT user_b_id) as num_friends
    FROM edges
    GROUP BY user_a_id
    UNION ALL
    SELECT user_b_id as user_id, COUNT(DISTINCT user_a_id) as num_friends
    FROM edges
    GROUP BY user_b_id)
  GROUP BY 
    user_id
)

SELECT
  t1.user_id,
  CASE
    WHEN t2.num_friends IS NULL THEN 0
    ELSE t2.num_friends
  END as num_friends
FROM
  users t1
LEFT JOIN
  tmp_t t2 ON t1.user_id = t2.user_id
ORDER BY 
  t2.num_friends DESC, t1.user_id

[ 논리 과정 ]

  1. user_a_id와 user_b_id의 페어가 unique 한지 확인
  2. user_a_id 기준 그룹핑하여 친구 수 집계
  3. user_b_id 기준 그룹핑하여 친구 수 집계
  4. 친구 수 집계한 두 테이블 합치기
  5. 최종 결과 조회하기

[ 문제 상황 ]

  • 오답 부분 코드
-- 오답 부분 코드  
WITH tmp_t AS (
  SELECT
    user_id,
    SUM(num_friends) as num_friends
  FROM
    (SELECT user_a_id as user_id, COUNT(DISTINCT user_b_id) as num_friends
    FROM edges
    GROUP BY user_a_id
    UNION
    SELECT user_b_id as user_id, COUNT(DISTINCT user_a_id) as num_friends
    FROM edges
    GROUP BY user_b_id)
  GROUP BY 
    user_id
)
  • 각 user_a_id, user_b_id 기준으로 친구 수 집계하여 합쳐서 조회해도 결과가 정답과 다르게 조회됨

[ 해결 ]

  1. 개수가 다르게 나왔던 원인은 UNION 이었음.
  2. UNION으로 합칠 시, 값이 동일한 데이터의 중복을 제거하고 합쳐지기 때문에 데이터 누수 발생
  3. UNION ALL을 통해 1차적으로 합쳐서 데이터 누수 없이 친구 수를 집계하고 user_id로 그룹핑

[ 회고 ]

  • 데이터를 조회해봤을 때, 눈에 데이터 누수가 보이지 않는다고 해서 데이터 누수가 발생하지 않은 것이 아니다.
  • 데이터를 병합하거나 분할하거나 조건을 걸어 조회할 때, 해당 쿼리가 원하는 결과를 조회하는데 작은 오류라도 발생시키지 않는지 꼼꼼하게 체크해야한다.
  • UNION과 UNION ALL의 차이는 중복 제거 여부이다. 중복 제거와 같이 데이터의 변형을 일으킬 수 있는 요소들을 꼼꼼하게 점검해야한다.