핵심 요약
존재 여부를 검사하는 IN·
학습 목표
- IN과 EXISTS의 논리적 의미를 설명한다.
- NOT IN의 NULL 함정을 NOT EXISTS와 비교한다.
본문
개념 지도
외부 행 단위→서브쿼리 반환 행 수→연산자 규칙→NULL·상관 여부 확인핵심 내용
IN은 왼쪽 값이 결과 집합 중 하나와 같은지 비교한다. EXISTS는 서브쿼리가 한 행이라도 반환하는지만 본다. 상관 EXISTS에서는 SELECT 목록 값보다 행의 존재가 중요하다.
SELECT d.deptno
FROM dept d
WHERE EXISTS (
SELECT 1 FROM emp e WHERE e.deptno = d.deptno
);
부정 조건에서는 NULL이 핵심이다. x NOT IN (1, 2, NULL)은 x<>1 AND x<>2 AND x<>NULL과 연결되며 마지막 비교가 UNKNOWN이므로 TRUE가 되기 어렵다.
SELECT d.deptno
FROM dept d
WHERE NOT EXISTS (
SELECT 1 FROM emp e WHERE e.deptno = d.deptno
);
미매칭을 찾을 때 NOT EXISTS는 조인 조건의 의미가 명확하다. NOT IN을 쓰려면 서브쿼리 결과에서 NULL이 절대 나오지 않음을 제약조건이나 조건으로 보장해야 한다.
NOT IN의 NULL 함정을 행별로 계산하기
DEPT.deptno = {10, 20, NULL}
EMP.deptno = {10, 30}
SELECT deptno
FROM emp
WHERE deptno NOT IN (SELECT deptno FROM dept);
30 <> 10 AND 30 <> 20 AND 30 <> NULL에서 마지막 비교가 UNKNOWN이므로 전체가 TRUE가 되지 않는다. 결과가 한 건도 없을 수 있다.
안전한 미존재 검사는 NULL 의미가 명확한 NOT EXISTS를 사용한다.
SELECT e.deptno
FROM emp e
WHERE NOT EXISTS (
SELECT 1
FROM dept d
WHERE d.deptno = e.deptno
);
서브쿼리 컬럼이 NOT NULL로 보장되거나 명시적으로 WHERE deptno IS NOT NULL을 추가하면 NOT IN과 같은 결과가 될 수 있지만, 제약과 업무 의미를 확인한다.
IN과 EXISTS의 의미
IN은 왼쪽 값이 오른쪽 값 집합에 속하는지 본다.EXISTS는 상관 조건을 만족하는 행이 하나라도 있는지 본다.- IN은 값의 소속 여부를, EXISTS는 조건을 만족하는 행의 존재 여부를 표현하므로 NULL과 상관 조건을 함께 확인한다.
ANY· ALL 연결
x > ANY(subquery)는 하나보다만 커도 되고, x > ALL(subquery)는 모든 값보다 커야 한다. 빈 집합·NULL 포함 시 3값 논리를 작은 데이터로 계산한다.
시험 포인트
부양가족이 없는 사원을 찾는 논리는 “현재 사원과 연결되는 가족 행이 존재하지 않는다”다.
-- 가장 직접적인 표현
SELECT e.name
FROM employee e
WHERE NOT EXISTS (
SELECT 1
FROM family f
WHERE f.employee_id = e.employee_id
);
-- 외부 조인으로 표현
SELECT e.name
FROM employee e
LEFT JOIN family f
ON f.employee_id = e.employee_id
WHERE f.employee_id IS NULL;
NOT IN도 사용할 수 있지만 서브쿼리 결과에 NULL이 있으면 전체가 UNKNOWN이 될 수 있다. FK가 NOT NULL인지 확인하거나 서브쿼리에서 NULL을 제거해야 한다.
SQL Server EXCEPT나 Oracle MINUS로 구한 차집합은 키 전체의 조합을 비교한다. 복합키 (A,B)의 차집합을 A NOT IN (SELECT A FROM t2) AND B NOT IN (SELECT B FROM t2)으로 각각 나누면 “같은 한 행” 비교가 아니므로 결과가 달라질 수 있다.
자주 틀리는 부분
- EXISTS 내부의
SELECT 1은 숫자 1과 비교한다는 뜻이 아니다. - IN과 EXISTS의 성능을 문법만 보고 항상 어느 쪽이 빠르다고 단정할 수 없다.
- NOT IN은 외부 값 자체가 NULL인 경우도 TRUE가 되지 않는다.
복습 문제
답을 생각한 뒤 정답과 근거를 펼쳐 보세요.
부서번호 목록에 NULL이 포함된 NOT IN 결과가 비는 이유는?
정답과 근거
각 후보와의 부등 비교에 UNKNOWN이 섞여 전체 조건이 TRUE가 되지 않기 때문입니다.
EXISTS가 확인하는 것은 컬럼 값인가, 행의 존재인가?
정답과 근거
SELECT 목록의 값이 아니라 조건을 만족하는 행이 하나라도 존재하는지를 확인합니다.
NOT IN 목록에 NULL이 섞인 경우 같은 반대 조건을 NOT EXISTS로 옮길 때 비교 키의 NULL 처리를 어떻게 명시해야 하는가?
정답과 근거
안쪽 비교는 inner.key = outer.key로 쓰고, 바깥 키가 NULL일 때 포함할지 제외할지를 outer.key IS NULL 또는 IS NOT NULL로 별도 명시해야 합니다.