•
집합 연산자로 두 조회 결과를 위아래(행)로 합칠 수 있다.
•
UNION 과 UNION ALL 의 차이(중복 제거·정렬·성능)를 설명할 수 있다.
•
INTERSECT(교집합)와 MINUS(차집합)를 사용할 수 있다.
•
집합 연산에서 ORDER BY 의 위치 규칙을 안다.
1. 집합 연산자란
1) 두 SELECT 결과를 세로로 합친다
네 가지 집합 연산자 | 의미 | 집합 기호 |
UNION | 합집합 (중복 제거) | A ∪ B |
UNION ALL | 합집합 (중복 유지) | A + B |
INTERSECT | 교집합 (공통) | A ∩ B |
MINUS | 차집합 (A에만) | A − B |
2. 사용 규칙 


두 SELECT의 ① 컬럼 개수, ② 순서, ③ 데이터 타입이 일치해야 한다.
-- ============================================================
-- 【시험용 예제】 규칙을 어기면 오류 ★★
-- ============================================================
-- ❌ 컬럼 개수가 다름
SELECT ENAME, SAL FROM EMP WHERE DEPTNO = 10
UNION
SELECT ENAME FROM EMP WHERE DEPTNO = 20; -- 컬럼 1개!
-- ORA-01789: query block has incorrect number of result columns
-- ❌ 데이터 타입이 다름 (2번째 컬럼: 숫자 vs 문자)
SELECT ENAME, SAL FROM EMP WHERE DEPTNO = 10
UNION
SELECT ENAME, JOB FROM EMP WHERE DEPTNO = 20; -- SAL(숫자) vs JOB(문자)
-- ORA-01790: expression must have same datatype as corresponding expression
-- ✅ 개수·순서·타입이 모두 일치
SELECT ENAME, SAL FROM EMP WHERE DEPTNO = 10
UNION
SELECT ENAME, SAL FROM EMP WHERE DEPTNO = 20; -- 정상 ✅
SQL
복사
1) 컬럼명은 첫 번째 SELECT 기준 
-- 결과의 컬럼명(헤더)은 '첫 번째' SELECT 것을 따른다
SELECT ENAME AS 사원명, SAL FROM EMP WHERE DEPTNO = 10
UNION
SELECT ENAME AS 이름, SAL FROM EMP WHERE DEPTNO = 20;
-- 사원명 SAL ← 헤더는 첫 SELECT의 '사원명' (두 번째 '이름' 은 무시됨)
-- ------ -----
-- ...
SQL
복사
두 번째 이후 SELECT의 컬럼명·별칭은 무시됩니다. 헤더는 항상 첫 SELECT 기준입니다.3. UNION vs UNION ALL 


이 단원 최다 출제입니다. 결과와 성능 두 관점으로 알아두세요.1) 핵심 차이
UNION | UNION ALL | |
중복 행 | 제거 | 그대로 유지 |
정렬 | 자동 정렬됨 | 정렬 안 함 |
성능 | 느림 (중복 제거·정렬 비용) | 빠름 |
권장 | 중복 제거가 필요할 때 | 중복이 없거나 상관없을 때 |
-- ============================================================
-- 【시험용 예제】 UNION 과 UNION ALL 의 결과 건수 차이 ★★★
-- 일부러 겹치는 조건으로 두 집합을 만든다
-- 집합A: 급여 2000 이상 집합B: 20번 부서
-- → 20번 부서이면서 급여 2000 이상인 사원(JONES,SCOTT,FORD)은 양쪽에 다 있다
-- ============================================================
-- UNION : 중복 제거 → 겹치는 사원은 한 번만
SELECT ENAME FROM EMP WHERE SAL >= 2000
UNION
SELECT ENAME FROM EMP WHERE DEPTNO = 20;
-- → 급여 2000이상(6명) + 20번부서(5명) 중 겹치는 3명 제거 = 8건
-- JONES, SCOTT, FORD 는 양쪽 조건을 다 만족하지만 '한 번만' 나온다
-- UNION ALL : 중복 유지 → 겹치는 사원은 두 번
SELECT ENAME FROM EMP WHERE SAL >= 2000
UNION ALL
SELECT ENAME FROM EMP WHERE DEPTNO = 20;
-- → 6 + 5 = 11건 (JONES, SCOTT, FORD 가 각각 두 번씩 나옴)
--
-- ⭐ 결과 건수가 다르다: UNION 8건 vs UNION ALL 11건
-- ⭐ 성능 관점: 중복이 없다는 것이 확실하면 UNION ALL 이 빠르다.
-- UNION 은 중복 제거를 위해 내부적으로 정렬(SORT)을 하기 때문이다.
SQL
복사
2) UNION 은 결과가 정렬되어 나온다
SELECT ENAME FROM EMP WHERE DEPTNO = 10
UNION
SELECT ENAME FROM EMP WHERE DEPTNO = 20;
-- ENAME
-- ------
-- ADAMS ← ORDER BY 를 안 썼는데도
-- CLARK 중복 제거 과정에서
-- FORD 자동으로 정렬되어 나온다
-- JONES
-- KING
-- ...
-- ⚠️ 단, 이 정렬은 '보장' 되는 게 아니므로 정렬이 필요하면 ORDER BY 를 명시해야 한다.
SQL
복사
4. INTERSECT — 교집합 
-- ============================================================
-- 【이해용 예제】 급여 2000 이상 '이면서' 20번 부서인 사원 ★
-- ============================================================
SELECT ENAME FROM EMP WHERE SAL >= 2000
INTERSECT
SELECT ENAME FROM EMP WHERE DEPTNO = 20;
-- ENAME
-- ------
-- FORD
-- JONES
-- SCOTT → 3건 (양쪽 집합에 모두 있는 사원)
--
-- ⭐ INTERSECT = 두 집합의 '공통' 부분만. 이것도 중복을 제거하고 정렬한다.
-- 같은 결과를 AND 조건으로도 낼 수 있다:
-- WHERE SAL >= 2000 AND DEPTNO = 20
SQL
복사
5. MINUS — 차집합 

1) A에는 있고 B에는 없는 것
-- ============================================================
-- 【이해용 예제】 급여 2000 이상이지만 20번 부서는 '아닌' 사원 ★
-- ============================================================
SELECT ENAME FROM EMP WHERE SAL >= 2000
MINUS
SELECT ENAME FROM EMP WHERE DEPTNO = 20;
-- ENAME
-- ------
-- BLAKE ← 30번, 급여 2850
-- CLARK ← 10번, 급여 2450
-- KING ← 10번, 급여 5000
-- → 3건 (급여 2000이상 6명 - 20번부서 3명 = 3명)
--
-- ⭐ 급여 2000이상 {JONES,BLAKE,SCOTT,KING,FORD,CLARK} 에서
-- 20번 부서 {JONES,SCOTT,FORD} 를 빼면 → {BLAKE,KING,CLARK}
SQL
복사
2)
순서가 결과를 바꾼다 

-- ============================================================
-- 【시험용 예제】 A MINUS B ≠ B MINUS A ★★
-- "10번 부서엔 있고 30번엔 없는 직무" vs 그 반대
-- ============================================================
-- 10번 - 30번 : 10번에만 있는 직무
SELECT JOB FROM EMP WHERE DEPTNO = 10
MINUS
SELECT JOB FROM EMP WHERE DEPTNO = 30;
-- JOB
-- ---------
-- PRESIDENT ← 10번엔 사장이 있고 30번엔 없다 → 1건
-- (MANAGER, CLERK 는 양쪽에 다 있어서 제외)
-- 30번 - 10번 : 30번에만 있는 직무 (순서를 바꿈)
SELECT JOB FROM EMP WHERE DEPTNO = 30
MINUS
SELECT JOB FROM EMP WHERE DEPTNO = 10;
-- JOB
-- ---------
-- SALESMAN ← 30번엔 영업사원이 있고 10번엔 없다 → 1건
--
-- ⭐ 순서에 따라 결과가 완전히 다르다. MINUS 는 '방향' 이 중요하다.
-- ⚠️ SQL Server 등 다른 DBMS 는 MINUS 대신 EXCEPT 를 쓴다 (기능은 동일).
SQL
복사
6. ORDER BY 의 위치 

ORDER BY 는 전체 집합 연산의 맨 마지막에 딱 한 번만.
-- ============================================================
-- 【시험용 예제】 ORDER BY 는 맨 끝에 한 번 ★★
-- ============================================================
-- ✅ 올바른 위치 : 전체의 맨 마지막
SELECT ENAME, SAL FROM EMP WHERE DEPTNO = 10
UNION
SELECT ENAME, SAL FROM EMP WHERE DEPTNO = 20
ORDER BY SAL DESC; -- 합쳐진 전체 결과를 정렬
-- → 두 집합을 합친 뒤 급여 내림차순으로 정렬
-- ❌ 중간 SELECT 에 ORDER BY 를 쓰면 오류
SELECT ENAME, SAL FROM EMP WHERE DEPTNO = 10
ORDER BY SAL -- 여기 쓰면 안 됨!
UNION
SELECT ENAME, SAL FROM EMP WHERE DEPTNO = 20;
-- ORA-00933: SQL command not properly ended
-- ⭐ ORDER BY 의 정렬 기준은 '첫 번째 SELECT' 의 컬럼명 또는 순번을 쓴다
SELECT ENAME AS 사원명, SAL FROM EMP WHERE DEPTNO = 10
UNION
SELECT ENAME, SAL FROM EMP WHERE DEPTNO = 20
ORDER BY 사원명; -- 첫 SELECT 의 별칭 '사원명' 사용 가능
-- 또는 ORDER BY 1; (컬럼 순번)
SQL
복사
규칙 | 내용 |
위치 | 전체의 맨 마지막에 한 번만 |
중간 SELECT | ORDER BY 불가 |
정렬 기준 | 첫 번째 SELECT 의 컬럼명/별칭/순번 |
7. NULL과 집합 연산
-- ============================================================
-- 【시험용 예제】 집합 연산자는 NULL 을 '같은 것' 으로 취급한다 ★
-- ============================================================
SELECT COMM FROM EMP WHERE DEPTNO = 20 -- 20번: 전원 COMM 이 NULL (5명)
UNION
SELECT COMM FROM EMP WHERE DEPTNO = 10; -- 10번: 전원 COMM 이 NULL (3명)
-- COMM
-- ------
-- (NULL) → 1건! NULL 8개가 '하나' 로 합쳐진다
--
-- ⭐ 06강에서 "NULL 끼리는 비교 불가(UNKNOWN)" 라고 했지만,
-- 집합 연산자(UNION/INTERSECT/MINUS)와 GROUP BY/DISTINCT 는
-- 예외적으로 NULL 을 '같은 값' 으로 취급한다. (07·11강 회수)
SQL
복사
8. 출제 포인트 한눈에 정리
# | 꼭 외울 것 | 핵심 |
1 | 집합 연산자 4종 | UNION UNION ALL INTERSECT MINUS |
2 | 조인 vs 집합 | 조인=가로(컬럼) / 집합=세로(행) |
3 | 사용 규칙 | 컬럼 개수·순서·타입 일치 ![]() |
4 | 규칙 위반 | ORA-01789(개수) / ORA-01790(타입) |
5 | 컬럼명 기준 | 첫 번째 SELECT |
6 | UNION | 중복 제거 + 정렬 (느림) |
7 | UNION ALL | 중복 유지 + 정렬 안 함 (빠름) ![]() |
8 | 성능 | 중복 없으면 UNION ALL 권장 |
9 | INTERSECT | 교집합 (공통) |
10 | MINUS | 차집합, 순서 중요 (A−B ≠ B−A) ![]() |
11 | MINUS 타 DBMS | SQL Server는 EXCEPT |
12 | ORDER BY 위치 | 맨 마지막 한 번만 ![]() |
13 | ORDER BY 기준 | 첫 SELECT 컬럼명/순번 |
14 | 집합 연산과 NULL | NULL을 같게 취급 |
9. 확인 문제
Q1. 집합 연산자를 사용하기 위한 조건으로 옳지 않은 것은?
① 두 SELECT의 컬럼 개수가 같아야 한다
② 대응하는 컬럼의 데이터 타입이 같아야 한다
③ 컬럼 순서가 일치해야 한다
④ 두 SELECT의 컬럼명이 완전히 같아야 한다
정답 보기
Q2. UNION 과 UNION ALL 의 차이는?
정답 보기
Q3. 두 집합의 행이 각각 6건, 5건이고 겹치는 행이 3건일 때, UNION 과 UNION ALL 의 결과 건수는?
정답 보기
Q4. A MINUS B 와 B MINUS A 의 결과가 다른 이유는?
정답 보기
Q5. 다음 두 SQL은 같은 결과를 내는가?
-- (A)
SELECT ENAME FROM EMP WHERE SAL>=2000 INTERSECT SELECT ENAME FROM EMP WHERE DEPTNO=20;
-- (B)
SELECT ENAME FROM EMP WHERE SAL>=2000 AND DEPTNO=20;
SQL
복사
정답 보기
Q6. 두 SELECT 모두 커미션이 NULL인 행만 반환할 때, UNION 하면 NULL은 몇 건 나오는가?
정답 보기






