집합 연산자: UNION·INTERSECT·MINUS
여러 SELECT 결과를 행 단위로 결합하며 중복 제거와 정렬 비용, 컬럼 호환 조건을 익힌다.
핵심 요약
여러 SELECT 결과를 행 단위로 결합하며 중복 제거와 정렬 비용, 컬럼 호환 조건을 익힌다.
핵심 질문
- 집합 연산자: UNION·INTERSECT·MINUS에서 반드시 구분해야 할 개념과 결과 규칙은 무엇인가?
- 0건·1건·여러 건과 NULL·동점·중복 데이터에서 결과가 어떻게 달라지는가?
- 비슷해 보이는 문법과 결과가 같아지는 조건, 달라지는 조건은 무엇인가?
- 작은 샘플 데이터를 이용해 결과를 실수 없이 예측하는 순서는 무엇인가?
학습 목표
- UNION·UNION ALL·INTERSECT·MINUS의 결과를 예측한다.
- 집합 연산이 가능한 SELECT 목록 조건을 설명한다.
개념 지도
각 SELECT의 컬럼 수·타입 정렬 → 집합 결합 → 중복 제거 여부 → 최종 ORDER BY
핵심 내용
집합 연산자는 두 질의 결과를 세로로 결합한다.
| 연산자 | 결과 | 중복 |
|---|---|---|
UNION ALL | 양쪽 결과 모두 | 유지 |
UNION | 합집합 | 제거 |
INTERSECT | 교집합 | 제거 |
MINUS | 왼쪽에서 오른쪽을 뺀 차집합 | 제거 |
각 SELECT는 컬럼 수가 같고 같은 위치의 데이터 타입 그룹이 호환되어야 한다. 최종 컬럼명은 첫 SELECT의 별칭을 기준으로 이해하고, 전체 정렬은 마지막에 한 번 작성한다.
SELECT customer_id AS id FROM online_order
UNION ALL
SELECT customer_id FROM store_order
ORDER BY id;
중복 제거가 필요하지 않다면 UNION ALL이 불필요한 정렬·해시 작업을 피할 수 있다. 그러나 업무적으로 중복 제거가 필요하면 성능만을 이유로 바꾸면 결과가 달라진다.
흔한 오해와 주의점
- 집합 연산은 열을 붙이는 조인과 달리 행을 이어 붙인다.
- 연산자가 섞인 식은 우선순위 변경 가능성과 가독성을 고려해 괄호로 의도를 명확히 한다.
- NULL도 중복 제거 과정에서는 같은 그룹으로 취급될 수 있다.
문항 풀이 보강: 집합 연산의 괄호와 동치
SQL Server의 EXCEPT는 Oracle의 MINUS와 같은 방향의 차집합이다.
SELECT a, b FROM tab1
EXCEPT
SELECT a, b FROM tab2;
이는 복합키 (a,b) 전체가 같은 TAB2 행이 존재하지 않는 TAB1 행을 찾는 NOT EXISTS로 바꿀 수 있다.
SELECT t1.a, t1.b
FROM tab1 t1
WHERE NOT EXISTS (
SELECT 1
FROM tab2 t2
WHERE t2.a = t1.a
AND t2.b = t1.b
);
UNION은 전체 결과 행 조합의 중복을 제거하고, UNION ALL은 보존한다. 첫 SELECT의 별칭이 최종 컬럼 이름이 되며 ORDER BY 1,2는 최종 SELECT 목록 위치를 뜻한다.
1:1 양쪽 필수 관계가 보장되면 두 테이블의 키 집합은 같다. 이때 INTERSECT 결과와 키 조인 결과 건수는 같고, EXCEPT는 공집합이며, UNION은 한 집합 크기지만 UNION ALL은 두 배가 된다.
작은 집합으로 결과 계산하기
A = {1, 1, 2, 3}
B = {2, 3, 4}
| 연산 | 결과 |
|---|---|
A UNION ALL B | 1, 1, 2, 3, 2, 3, 4 |
A UNION B | 1, 2, 3, 4 |
A INTERSECT B | 2, 3 |
A MINUS B | 1 |
MINUS는 방향이 있으므로 B MINUS A는 4가 된다. 집합 연산의 중복 제거는 전체 Row 조합을 기준으로 한다.
타입과 ORDER BY
SELECT employee_id AS id, hire_date AS dt FROM employee
UNION ALL
SELECT customer_id, created_at FROM customer
ORDER BY id;
각 위치의 데이터 타입 그룹이 호환되어야 하고 최종 Column 이름은 첫 SELECT를 기준으로 한다. Branch별 ORDER BY는 일반적인 최종 결과 순서를 보장하지 않으므로 전체 집합 뒤에 한 번 작성한다. Branch 내부 Top-N이 필요하면 별도 Query Block으로 감싼다.
NULL과 집합 비교
집합 연산의 중복 제거에서는 같은 위치의 NULL을 중복 판단에 같은 값처럼 취급한다. 이는 NULL = NULL이 TRUE라는 뜻이 아니라 집합 중복 제거 규칙이다.
성능 판단
UNION, INTERSECT, MINUS는 Sort 또는 Hash로 중복·존재 비교 작업을 수행할 수 있다. 중복 제거가 업무상 필요 없을 때만 UNION ALL로 바꾼다. Branch가 상호 배타적임을 Predicate로 증명할 수 있으면 UNION ALL이 안전한 대안이 된다.
결과를 검증하는 순서
- 각 Query Block이 만드는 한 행의 의미를 먼저 적습니다.
- 조건을 적용하기 전 원본 행과 적용 후 남는 행을 작은 표로 그립니다.
- NULL 비교가
TRUE,FALSE,UNKNOWN중 무엇인지 구분합니다. - 중복 제거, 그룹화, 정렬과 행 제한이 적용되는 순서를 확인합니다.
- 데이터가 0건·1건·여러 건일 때도 같은 규칙이 성립하는지 검증합니다.
실무와 시험에서 함께 확인할 항목
ORDER BY가 없다면 결과 순서를 가정하지 않습니다.- 문자열·숫자·날짜 비교에서는 데이터 타입과 명시적 형변환을 확인합니다.
- 같은 결과처럼 보이는 SQL도 NULL과 중복이 있을 때 달라질 수 있습니다.
- 문법을 외우기 전에 샘플 데이터 3~5행으로 결과를 직접 계산합니다.
마지막 점검
- 작성 순서가 아니라 SQL의 논리적 처리 순서로 결과를 계산합니다.
- NULL을 0이나 빈 값과 같은 것으로 취급하지 않습니다.
ORDER BY가 없는 결과 순서와 DISTINCT 없는 중복 제거를 가정하지 않습니다.- 비슷한 문법은 0건·다건·NULL 데이터를 넣어 결과가 정말 같은지 확인합니다.
복습 문제
- 중복을 보존하는 합집합 연산자는?
- 두 SELECT의 컬럼 이름까지 같아야 하는가?
- 샘플 데이터 3행으로 결과를 직접 계산할 수 있는가?
- NULL이 포함될 때 결과가 달라지는 지점은 어디인가?