공공부하자개발 · 영어 학습 노트
SQL
SQL 중급서브쿼리·조인·함수·DDL·인덱스0/11 완료
  • 01서브쿼리: 스칼라·인라인 뷰·상관 서브쿼리, DB별 차이
  • 02EXISTS·IN·NOT IN 과 NULL 함정
  • 03조인 심화: INNER·OUTER·SELF·CROSS, Oracle (+)
  • 04집합 연산: UNION·UNION ALL·INTERSECT·MINUS/EXCEPT
  • 05조건 로직: CASE·DECODE·IIF
  • 06NULL 처리 함수
  • 07문자·날짜 함수 DB별 비교
  • 08DDL 과 제약 조건
  • 09인덱스 기초
  • 10집계와 GROUP BY·HAVING
  • 11뷰·시퀀스·자동 증가
사이트 소개개인정보처리방침연락처
© 2026 공부하자
홈 › SQL 중급 › 04 / 11

집합 연산: UNION·UNION ALL·INTERSECT·MINUS/EXCEPT

섹션 6진행 0 / 11
1왜 배우는가2핵심 원리3코드 예제4응용 변형 예제5자주 하는 실수 (Tip)6정리‹ 이전다음 ›

4. 응용 변형 예제

소스: sql-src/mid_04_set_ops/02_intersect_except.sql, 03_dialects.sql. NULL 을 보는 관점 차이, 두 테이블 대사 패턴, DB 별 문법 차이를 확인합니다.

변형 1: 집합 연산과 = 비교의 NULL 처리 차이

sql
SELECT NULL AS v
INTERSECT
SELECT NULL AS v;
text
V
----
NULL
(1행)
sql
SELECT CASE WHEN NULL = NULL THEN 'Y' ELSE 'N' END AS eq;
text
EQ
--
N
(1행)

INTERSECT 는 양쪽의 NULL 을 같은 값으로 보고 1행을 남겼습니다. 반면 = 로 NULL 과 NULL 을 비교하면 UNKNOWN 이 되어 CASE 의 ELSE(N)로 빠집니다. 같은 "NULL 끼리 비교"인데 두 문법의 결론이 다릅니다.

변형 2: 두 테이블 대사 준비 — old_orders · new_orders

old_orders(이관 전 원본)와 new_orders(이관 후 복사본)를 준비했습니다. 401·403·405 번은 그대로 옮겨졌고, 402 번은 금액이 300에서 350으로 바뀌었고, 404 번은 새 시스템으로 안 옮겨졌고, 406 번은 원본에는 없던 행이 새 시스템에만 있습니다.

변형 3: INTERSECT — 완전히 같은 행만(정상 대사)

sql
SELECT
       id
     , cust
     , amt
     , status
  FROM old_orders
INTERSECT
SELECT
       id
     , cust
     , amt
     , status
  FROM new_orders
 ORDER BY id;
text
ID  | CUST     | AMT | STATUS
----+----------+-----+-------
401 | 가나상사 | 500 | 완료
403 | 마바유통 | 700 | 완료
405 | 자차상사 | 450 | 완료
(3행)

모든 컬럼 값이 완전히 같은 행 3개만 남았습니다. 이관이 정확했다고 확인할 수 있는 행입니다.

변형 4: EXCEPT — 이관 전에만 있는 행

sql
SELECT
       id
     , cust
     , amt
     , status
  FROM old_orders
EXCEPT
SELECT
       id
     , cust
     , amt
     , status
  FROM new_orders
 ORDER BY id;
text
ID  | CUST     | AMT | STATUS
----+----------+-----+-------
402 | 다라전자 | 300 | 완료
404 | 사아물산 | 200 | 취소
(2행)

old_orders 의 값 그대로는 new_orders 어디에도 없는 행입니다. 402 번은 금액이 바뀌어 원래 값(300)이 새 테이블에 없고, 404 번은 아예 이관되지 않았습니다.

변형 5: EXCEPT — 반대 방향으로 이관 후에만 있는 행

sql
SELECT
       id
     , cust
     , amt
     , status
  FROM new_orders
EXCEPT
SELECT
       id
     , cust
     , amt
     , status
  FROM old_orders
 ORDER BY id;
text
ID  | CUST     | AMT | STATUS
----+----------+-----+-------
402 | 다라전자 | 350 | 완료
406 | 카타무역 | 150 | 보류
(2행)

402 번은 바뀐 값(350)으로 여기 다시 나타나고, 406 번은 원본에 없던 행입니다. 변형 4 와 이 결과를 같이 보면 402 번은 "값이 바뀐 행", 404 번은 "빠진 행", 406 번은 "새로 생긴 행"이라고 정확히 구분됩니다.

핵심

두 테이블을 대사할 때는 A EXCEPT B 와 B EXCEPT A 를 함께 봐야 합니다. 한쪽만 보면 "달라진 행"인지 "한쪽에만 있는 행"인지 구분할 수 없습니다.

변형 6: DB 별 차이

기능 Oracle · Tibero MySQL MSSQL
차집합 키워드 MINUS, 21c 부터 EXCEPT 도 EXCEPT(8.0.31 부터) EXCEPT
INTERSECT 지원 지원(8.0.31 부터) 지원(2005 부터)
INTERSECT ALL · EXCEPT ALL Oracle 21c 부터, Tibero 미지원 지원(8.0.31 부터) 미지원(DISTINCT 만)
8.0.30 이하 대체 - NOT EXISTS·LEFT JOIN -
sql
-- Oracle · Tibero
SET MODE Oracle;
SELECT
       cust
  FROM orders_2024
MINUS
SELECT
       cust
  FROM orders_2025
 ORDER BY cust;
text
CUST
--------
다라전자
사아물산
자차상사
카타무역
(4행)

Oracle·Tibero 는 EXCEPT 대신 MINUS 를 씁니다. SET MODE Regular·SET MODE MySQL·SET MODE MSSQLServer 로 바꿔 같은 쿼리를 EXCEPT 로 실행해도 결과는 똑같이 이 4행입니다. MINUS 는 Oracle 계열의 이름일 뿐 동작은 EXCEPT 와 같고, Oracle 21c 부터는 EXCEPT 라고 써도 됩니다.

H2 의 MySQL 모드는 버전을 흉내 내지 않아 EXCEPT 가 그대로 실행됩니다. 실제 MySQL 8.0.30 이하에서는 EXCEPT·INTERSECT 키워드 자체가 없어 문법 오류가 납니다. 이 버전 제약은 H2 로 재현할 수 없어 문법 검토만 했습니다.

8.0.30 이하라면 WHERE NOT EXISTS (...) 로 같은 결과를 만듭니다. sql-src/mid_04_set_ops/03_dialects.sql 에서 직접 실행해 위 MINUS 예제와 똑같이 4행이 나오는 것을 확인해 뒀습니다(중급 02 의 NOT EXISTS 안티 조인과 같은 패턴).

MSSQL 은 2005 버전부터 EXCEPT·INTERSECT 를 지원하며 MINUS 라는 이름은 쓰지 않지만, 결과는 다른 DB 와 동일합니다.

sql
SELECT cust FROM orders_2024 INTERSECT ALL SELECT cust FROM orders_2025;
text
예상 오류: Syntax error in SQL statement

INTERSECT ALL·EXCEPT ALL 은 H2 자체가 지원하지 않아 문법 검토만 했습니다(2.5절 표 참고). MySQL 8.0.31 이상이라면 실제로 지원하는 문법이지만, H2 로는 재현할 수 없습니다.

주의

"EXCEPT/INTERSECT 를 쓸 수 있는가"와 "ALL 옵션까지 쓸 수 있는가"는 DB 마다 별개의 질문입니다. 배포 대상 DB 와 버전을 먼저 확인하고, 확신이 없으면 표준 DISTINCT(기본값) 동작만 쓰는 편이 안전합니다.

응용 변형 예제
  • 변형 1: 집합 연산과 = 비교의 NULL 처리 차이
  • 변형 2: 두 테이블 대사 준비 — old_orders · new_orders
  • 변형 3: INTERSECT — 완전히 같은 행만(정상 대사)
  • 변형 4: EXCEPT — 이관 전에만 있는 행
  • 변형 5: EXCEPT — 반대 방향으로 이관 후에만 있는 행
  • 변형 6: DB 별 차이
이전 섹션3 코드 예제4 / 6다음 섹션5 자주 하는 실수 (Tip)