자격증/SQLD

SQLD 서브쿼리 정리, 위치로 종류 구분하기

공감(공부하는감자) 2026. 6. 23. 13:56

안녕하세요, 공부하는 감자입니다 🥔

서브쿼리 공부할 때 스칼라, 인라인 뷰, 중첩, 상관… 이름부터 외우려다 포기할 뻔했어요. 그런데 알고 보니 외울 필요가 없더라고요.

서브쿼리가 어느 절에 있는지만 보면 이름이 자동으로 따라옵니다.

위치 이름 핵심 제약
SELECT 절 스칼라 서브쿼리 1행 1컬럼만 반환 가능
FROM 절 인라인 뷰 가상 테이블, ALIAS 필수
WHERE 절 중첩 서브쿼리 단일행/다중행 구분
WHERE 절 + 메인 컬럼 참조 상관 서브쿼리 메인 행마다 재실행

SQLD 2과목에서 서브쿼리는 매회 3~4문제 고정 출제인데, 출제 포인트도 정해져 있어요. "이 서브쿼리는 몇 행을 반환하는가"와 "함정을 알아채는가", 사실상 이 둘이 전부입니다.

SELECT 절: 스칼라 서브쿼리

컬럼 자리에 들어가는 서브쿼리예요. 반드시 행 하나, 컬럼 하나만 내놔야 합니다.

SELECT o.order_no,
       o.amount,
       (SELECT c.cust_name FROM CUSTOMER c
         WHERE c.cust_id = o.cust_id) AS cust_name
  FROM ORDERS o;

시험 포인트 세 개.

  • 결과가 2행 이상 → 실행 오류
  • 결과가 0행 → 오류가 아니라 NULL 반환 (여기서 정말 많이 틀려요)
  • 컬럼이 2개 이상 → 오류

"0행이면 오류"라는 보기가 함정으로 단골 출제됩니다. 오류 아니고 NULL입니다.

FROM 절: 인라인 뷰

FROM 자리에 들어가면 가상 테이블 취급이에요. 별칭을 붙여서 일반 테이블처럼 조인합니다.

SELECT c.cust_name, t.avg_amt
  FROM (SELECT cust_id, AVG(amount) AS avg_amt
          FROM ORDERS
         GROUP BY cust_id) t
  JOIN CUSTOMER c ON c.cust_id = t.cust_id;

기억할 것은 두 가지. 인라인 뷰 안에서는 메인 쿼리의 컬럼을 참조할 수 없다는 것(참조하면 오류), 그리고 TOP-N 패턴의 재료라는 것.

SELECT *
  FROM (SELECT * FROM ORDERS ORDER BY amount DESC)
 WHERE ROWNUM <= 3;

"인라인 뷰에서 정렬해놓고 바깥에서 ROWNUM으로 자르기" — 이 구조가 SQLD 단골 출제 패턴입니다. ROWNUM을 정렬 전에 매기면 안 되니까 꼭 이 순서여야 해요.

WHERE 절: 단일행이냐 다중행이냐

메인 컬럼을 참조하지 않는 WHERE 절 서브쿼리는 한 번만 실행되고, 그 결과를 메인 쿼리가 받아 씁니다. 이때 결과 행 수에 따라 쓸 수 있는 연산자가 갈려요.

단일행이면 비교 연산자(=, >, < 등)와 같이 씁니다.

SELECT order_no, amount
  FROM ORDERS
 WHERE amount > (SELECT AVG(amount) FROM ORDERS);

이때 서브쿼리 결과가 2행 이상이면 런타임 오류예요. "비교 연산자 + 다중행 결과 = 오류" 조합을 묻는 문제가 꼭 나옵니다.

다중행이면 전용 연산자를 씁니다.

연산자 의미
IN 결과 중 하나라도 일치
ANY (SOME) 하나라도 조건 만족 → > ANY는 최솟값보다 크면 통과
ALL 전부 조건 만족 → > ALL은 최댓값보다 커야 통과
EXISTS 행이 하나라도 있으면 TRUE

> ANY(10, 20, 30)은 10보다 크면 되고, > ALL(10, 20, 30)은 30보다 커야 합니다.

"ANY는 최소, ALL은 최대"로 외우면 끝.

상관 서브쿼리: 행마다 다시 실행

WHERE 절 서브쿼리인데 메인 쿼리의 별칭을 안에서 참조하면 상관 서브쿼리입니다.

SELECT o.order_no, o.amount
  FROM ORDERS o
 WHERE o.amount > (SELECT AVG(amount)
                     FROM ORDERS
                    WHERE cust_id = o.cust_id);

"각 주문이 그 고객의 평균 주문액보다 큰가?"를 묻는 쿼리예요. 비상관 서브쿼리는 딱 1번 실행되지만, 상관 서브쿼리는 메인 쿼리 행 수만큼 반복 실행됩니다.

SQLD에서 이 "실행 횟수" 차이를 묻기도 해요.

최종 보스: NOT IN + NULL

서브쿼리 영역에서 가장 악명 높은 함정이고, 매회 한 문제는 나온다고 봐도 됩니다.

SELECT c.cust_id FROM CUSTOMER c
 WHERE c.cust_id NOT IN (SELECT cust_id FROM BLACKLIST);
-- BLACKLIST.cust_id에 NULL이 하나라도 있으면 → 0행

NULL이 섞인 목록과의 NOT IN 비교는 3치 논리에서 UNKNOWN이 되어 결과가 통째로 비어버립니다. 회피법은 두 가지예요.

-- 서브쿼리에서 NULL 제거
WHERE cust_id NOT IN (SELECT cust_id FROM BLACKLIST
                       WHERE cust_id IS NOT NULL);

-- 또는 NOT EXISTS (권장)
WHERE NOT EXISTS (SELECT 1 FROM BLACKLIST b
                   WHERE b.cust_id = c.cust_id);

비슷한 맥락에서 IN과 EXISTS 비교 문제도 나옵니다. IN은 값 집합을 통째로 받아 비교하고, EXISTS는 행 존재 여부(TRUE/FALSE)만 봐요.

NULL의 영향을 받지 않는 쪽은 EXISTS입니다. "NULL 가능성이 있으면 EXISTS"만 기억하면 안전해요.

풀이 루틴 5단계

  1. 위치 식별 — SELECT/FROM/WHERE 어느 절인가
  2. 반환 행 수 추정 — 1행인가 N행인가 0행인가
  3. 메인 컬럼 참조 여부 — 있으면 상관
  4. NOT IN이 보이면 NULL 의심
  5. ANY/ALL이 보이면 최솟값/최댓값 대입

이 순서를 기계적으로 돌리면 서브쿼리 문제는 함정이 정형화되어 있어서 점수 회수율이 높습니다. 저는 이 유형만 골라 반복하려고 모의고사를 회차별로 돌렸는데, 그때 쓴 게 문어CBT였어요.

 

SQLD·정처기·컴활·ADsP 무료 CBT 모의고사

기출 변형 문제, 자동 채점, 회차별 실력 추적까지 가입 없이 바로 풀어보세요.

sqldpass.com

무료인데 해설이 달려 있어서 틀린 서브쿼리 문제 복기할 때 도움이 됐습니다.

위치가 이름이고, 행 수가 정답입니다. 서브쿼리는 이 두 문장으로 요약돼요.