서브쿼리: Single·Multi·Correlated

SQL 기본 및 활용 · 서브쿼리

이 페이지의 목차

핵심 요약

단일행·다중행·상관 서브쿼리를 반환 행 수와 외부 행 의존성으로 구분한다.

단일행·다중행·상관 서브쿼리의 결과 규칙은 SQL 공통으로 다루고, Unnesting·Scalar Subquery Cache 같은 물리 최적화는 Oracle SQLP 범위에서 별도로 확인한다.

학습 목표

  • 서브쿼리 반환 건수에 맞는 연산자를 선택한다.
  • 상관 서브쿼리가 외부 쿼리의 행을 참조하는 방식을 설명한다.

본문

개념 지도

도식
외부 행 단위→서브쿼리 반환 행 수→연산자 규칙→NULL·상관 여부 확인

핵심 내용

서브쿼리는 다른 SQL 안에 포함된 질의다. 위치에 따라 스칼라 서브쿼리, 인라인 뷰, WHERE 서브쿼리 등으로 사용된다.

단일행 서브쿼리는 0 또는 1행을 기대하며 =, <, > 같은 단일행 연산자를 쓴다. 여러 행을 반환할 수 있으면 IN, ANY, ALL, EXISTS 같은 연산자가 필요하다.

SQL
SELECT e.empno, e.sal
FROM emp e
WHERE e.sal > (
  SELECT AVG(sal) FROM emp
);

상관 서브쿼리는 내부 쿼리가 외부 행의 값을 참조한다.

SQL
SELECT e.empno
FROM emp e
WHERE e.sal > (
  SELECT AVG(x.sal) FROM emp x WHERE x.deptno = e.deptno
);

상관 서브쿼리는 외부 Query의 현재 행 값을 참조하며, 각 외부 행에 대해 조건의 참·거짓을 판단하는 형태로 해석한다.

반환 행 수와 연산자 맞추기

서브쿼리 결과사용할 수 있는 대표 연산자다건일 때
Scalar 0·1행=, <, >2행 이상이면 ORA-01427
Multi RowIN, ANY, ALL, EXISTS집합 규칙으로 평가
Correlated외부 행마다 논리적으로 평가Unnesting·Cache 가능
SQL
SELECT ename
FROM emp
WHERE sal > (SELECT AVG(sal) FROM emp);

집계 Scalar Subquery는 입력이 0행이어도 AVG 결과 한 행(NULL)을 반환한다는 점과, 일반 Scalar Subquery의 0행→NULL 규칙을 구분한다.

ANY와 ALL

도식
x > ANY(10,20,30)→최소값 10보다 크면 참 가능x > ALL(10,20,30)→최대값 30보다 커야 참

빈 집합과 NULL이 포함되면 결과가 달라지므로 논리식을 직접 계산한다.

상관 서브쿼리

SQL
SELECT d.deptno
FROM dept d
WHERE EXISTS (
  SELECT 1 FROM emp e
  WHERE e.deptno = d.deptno
  AND e.status = 'ACTIVE'
);

IN과 EXISTS는 NULL과 중복의 영향까지 같을 때에만 서로 바꿔 쓸 수 있다. 문법 모양만 보고 두 표현이 항상 같은 결과라고 판단하지 않는다.

변환 주의

Scalar를 Join으로 바꾸면 오른쪽 중복 때문에 외부 행 수가 늘 수 있다. 0건→NULL, 다건→오류라는 원래 의미를 보존하는지 먼저 확인한다.


시험 포인트

문항 풀이 보강: 다중행 비교와 그룹별 최신 행

표현의미
x > ANY (subquery)결과 중 하나보다 크면 됨, 사실상 최솟값보다 큼
x > ALL (subquery)모든 결과보다 커야 함, 사실상 최댓값보다 큼
x IN (subquery)결과 중 같은 값이 하나라도 있음
EXISTS (subquery)조건을 만족하는 행이 하나라도 존재

서브쿼리가 빈 집합일 때 ANY와 ALL의 논리 결과도 구분한다. NULL이 섞이면 3값 논리를 함께 적용한다.

그룹별 최초·최신 한 행

광고매체별 최초 광고처럼 “그룹별 한 행”을 구할 때 단순 MIN(날짜)만 선택하면 같은 행의 광고명을 함께 가져오지 못할 수 있다.

SQL
SELECT *
FROM (
  SELECT p.*,
         ROW_NUMBER() OVER (
           PARTITION BY media_id
           ORDER BY start_dt, post_id
         ) rn
  FROM ad_post p
)
WHERE rn = 1;

상관 서브쿼리로 현재 행보다 더 빠른 행이 없는지 검사하거나, 집계 결과를 원본과 다시 조인하는 방법도 있다. 동점 처리 기준까지 명시해야 결과가 결정적이다.

스칼라 서브쿼리

SELECT 목록의 스칼라 서브쿼리는 0행이면 NULL, 정확히 1행이면 그 값, 2행 이상이면 오류다. COUNT(*) 집계는 입력이 없어도 0 한 행을 반환하므로 부양가족 수 같은 계산에 사용할 수 있다.

문제에 적용하는 순서

  1. 서브쿼리가 몇 행을 반환할 수 있는지 판단한다.
  2. 외부 행을 참조하는 상관 조건을 표시한다.
  3. 단일행 연산자와 다중행 연산자가 맞는지 본다.
  4. 그룹별 한 행이면 동점과 연결 컬럼의 일관성을 확인한다.

자주 틀리는 부분

  • = 뒤 서브쿼리가 두 행 이상 반환하면 단일행 서브쿼리 오류가 난다.
  • 스칼라 서브쿼리가 0행이면 NULL, 두 행 이상이면 오류다.
  • 상관 서브쿼리의 논리적 의미와 실제 반복 실행 횟수를 동일시하지 않는다.

복습 문제

답을 생각한 뒤 정답과 근거를 펼쳐 보세요.

01

부서별 평균보다 급여가 높은 사원을 찾는 서브쿼리는 왜 상관 서브쿼리인가?

정답과 근거

안쪽 평균 계산이 바깥 사원의 부서번호를 참조해 사원 행마다 해당 부서의 평균을 구하기 때문입니다.

02

다중행 결과에 =를 사용하면 어떻게 되는가?

정답과 근거

단일행 비교 연산자 =에 두 행 이상이 반환되면 오류가 발생합니다.

03

상관 서브쿼리가 바깥 사원의 부서번호를 참조할 때 평가 단위는 전체 쿼리 한 번인가, 바깥 행마다인가?

정답과 근거

논리적으로 바깥 행마다 평가합니다. 다만 옵티마이저가 의미를 보존하며 조인으로 변환할 수 있으므로 물리 실행 횟수는 계획으로 확인합니다.