✅ UNION / UNION ALL 완전 정복
🧠 1. 기본 개념
연산자 | 설명 |
---|---|
UNION |
중복 제거하면서 두 SELECT 결과를 수직으로 합침 |
UNION ALL |
중복 포함한 채로 두 SELECT 결과를 수직으로 합침 |
🔻 공통점:
- SELECT 결과의 컬럼 수와 순서, 타입이 같아야 함
✅ 2. 기본 사용 예시
📍 예시 테이블
-- 테이블 1: 고객 문의
SELECT '문의' AS type, user_id, created_at FROM inquiries
-- 테이블 2: 고객 불만 접수
SELECT '불만' AS type, user_id, created_at FROM complaints
✅ UNION
SELECT '문의' AS type, user_id, created_at FROM inquiries
UNION
SELECT '불만' AS type, user_id, created_at FROM complaints;
- 중복된
(user_id, created_at)
값은 한 번만 표시됨
✅ UNION ALL
SELECT '문의' AS type, user_id, created_at FROM inquiries
UNION ALL
SELECT '불만' AS type, user_id, created_at FROM complaints;
- 중복도 전부 포함 → 성능 빠름
✅ 3. 컬럼 수/타입이 다르면 오류
-- ❌ 오류: 컬럼 수가 다름
SELECT id, name FROM users
UNION
SELECT email FROM newsletters;
✔️ 반드시 컬럼 수, 타입 맞춰줘야 함
-- ✅ 해결 방법
SELECT id, name FROM users
UNION
SELECT NULL, email FROM newsletters;
✅ 4. 정렬 적용
ORDER BY
는 UNION 전체 결과에 한 번만 사용- UNION ALL 이후 정렬하고 싶다면 전체 쿼리를 서브쿼리로 감싸야 함
SELECT name, email FROM customers
UNION ALL
SELECT name, email FROM suppliers
ORDER BY name; -- ✅ 가능
-- 또는
SELECT * FROM (
SELECT name, email FROM customers
UNION ALL
SELECT name, email FROM suppliers
) AS all_people
ORDER BY name;
✅ 5. 실무 예제
📌 예제 1: 전체 활동 이력 통합 조회
SELECT user_id, '로그인' AS activity, login_time AS event_time FROM user_logins
UNION ALL
SELECT user_id, '주문' AS activity, order_date FROM orders
UNION ALL
SELECT user_id, '문의' AS activity, inquiry_date FROM inquiries
ORDER BY user_id, event_time DESC;
📌 여러 테이블의 활동 기록을 하나의 타임라인으로 합침
📌 예제 2: 탈퇴 회원 + 휴면 회원 조회 (중복 제거 필요)
SELECT id, email FROM withdrawn_users
UNION
SELECT id, email FROM dormant_users;
📌 동일 회원이 탈퇴 후 휴면으로 다시 등록된 경우 → 중복 제거됨
📌 예제 3: 중복 포함 매출 로그 통합
SELECT * FROM online_sales
UNION ALL
SELECT * FROM offline_sales;
📌 매출 내역은 중복되더라도 모두 집계가 중요 ⇒ UNION ALL
✅ 6. 성능 비교: UNION vs UNION ALL
항목 | UNION | UNION ALL |
---|---|---|
중복 제거 | ✅ | ❌ |
정렬 발생 | ✅ (암묵적) | ❌ |
속도 | 느림 | 빠름 |
실무 사용 빈도 | 중복 방지 필요 시 사용 | 기본값으로 더 자주 사용됨 |
⚠️ 성능 주의
UNION
은 내부적으로DISTINCT
+ 정렬 연산이 포함되어 매우 느릴 수 있음- 행 수가 많은 쿼리라면
UNION ALL
을 기본으로 사용하고, 필요한 경우만 DISTINCT 처리
✅ 7. 실무에서 자주 쓰는 상황 정리
상황 | 사용 예시 |
---|---|
여러 이력 테이블 통합 | UNION ALL |
중복 방지된 결과로 통합 조회 | UNION |
JOIN 대신 풀아웃터 조인 구현 | LEFT JOIN UNION RIGHT JOIN |
다국적 이메일 리스트 합치기 | UNION ALL |
A 또는 B 조건 만족한 사용자 조회 | UNION 또는 OR , 필요 시 UNION 사용 |
✅ 8. FULL OUTER JOIN 대체 패턴 (복습)
MySQL에는 FULL OUTER JOIN이 없기 때문에, 다음과 같이 UNION
으로 대체함:
-- A에는 있지만 B에는 없는 경우 포함
SELECT a.id, a.value, b.value
FROM a
LEFT JOIN b ON a.id = b.id
UNION
-- B에는 있지만 A에는 없는 경우 포함
SELECT a.id, a.value, b.value
FROM a
RIGHT JOIN b ON a.id = b.id;
📌 LEFT JOIN + RIGHT JOIN을 UNION
으로 합쳐서 FULL OUTER JOIN 흉내냄
✅ 9. 정리 요약
항목 | UNION | UNION ALL |
---|---|---|
중복 제거 | O | X |
정렬 포함됨? | 암묵적 있음 (DISTINCT) | 없음 |
성능 | 느림 | 빠름 |
주 용도 | 결과 중복 제거 필요 시 | 로그, 이력 통합 등 일반적인 합치기 |
실무 팁 | 기본은 UNION ALL , 필요 시 DISTINCT 으로 정제 |
✅ |
✅ UNION / UNION ALL에서 컬럼 수 & 타입 제한
조건 | 설명 |
---|---|
📌 컬럼 수 같아야 함 | SELECT 절의 컬럼 개수가 동일해야 함 |
📌 컬럼 순서 같아야 함 | 1번째, 2번째… 같은 순서로 비교됨 |
📌 데이터 타입 호환돼야 함 | 같은 위치의 컬럼끼리 유사한 타입이어야 함 (예: INT와 VARCHAR 같이 사용 ❌) |
이건 SQL 표준이기 때문에 MySQL뿐 아니라 Oracle, PostgreSQL, SQL Server 모두 똑같이 적용됨.
❌ 잘못된 예시: 컬럼 수 안 맞음
SELECT id, name FROM users
UNION ALL
SELECT email FROM subscribers;
-- 🚨 오류: SELECT 절의 컬럼 개수가 다릅니다
✅ 해결 예시: NULL 또는 상수로 맞추기
SELECT id, name FROM users
UNION ALL
SELECT NULL AS id, email AS name FROM subscribers;
- 이렇게 누락된 컬럼에는
NULL
이나 상수값을 넣어서 맞춰줌 - 실무에서 종종 쓰이는 패턴
❌ 잘못된 예시: 타입 불일치
SELECT id, name FROM users -- id: INT, name: VARCHAR
UNION ALL
SELECT name, birth_date FROM people -- name: VARCHAR, birth_date: DATE
id
(INT)와name
(VARCHAR)가 같은 위치 → 타입 불일치
✅ 해결 예시: CAST 또는 타입 맞추기
SELECT id, name FROM users
UNION ALL
SELECT CAST(name AS UNSIGNED), birth_date FROM people;
💡 실무 팁
상황 | 해결 전략 |
---|---|
컬럼 수가 다름 | NULL , DEFAULT , 상수 로 컬럼 추가 |
타입이 다름 | CAST() , CONVERT() 로 강제 변환 |
헤더 통일 | AS alias 로 컬럼 이름 맞추기 |
정렬 기준 컬럼 정하기 | UNION ALL 결과를 서브쿼리로 감싸서 ORDER BY 적용 |
✅ 실전 예: 두 테이블 통합
-- 고객 문의 기록 + 이메일 구독 기록 통합 조회
SELECT user_id, created_at, '문의' AS type FROM inquiries
UNION ALL
SELECT NULL AS user_id, subscribed_at AS created_at, '구독' AS type FROM subscribers;
- 컬럼 수: 3개로 맞춤
- 타입: user_id는 NULL 가능, 날짜 형식 통일
- 정렬도 가능
'CS > Database' 카테고리의 다른 글
[MySQL] Query Cost가 높아지는 조건과 성능 개선 포인트 (0) | 2025.04.13 |
---|---|
[MySQL] UNION / UNION ALL 결과의 고급 활용 예제 (0) | 2025.04.13 |
[MySQL] MySQL의 JOIN 완전 정복 + FULL OUTER JOIN 대체 방법 (0) | 2025.04.13 |
[MySQL] SubQuery 사용 (0) | 2025.04.13 |
[MySQL] GROUP BY / HAVING 관련 SELECT 컬럼 정리 + 인라인 뷰 (inline view) 활용법 (0) | 2025.04.13 |
댓글