모든 강의를 무료로 볼 수 있어요. 회원가입 없이도 학습 가능합니다.

16강 / 전체 24강

서브쿼리

7분 읽기 조회 0

SELECT 안에 SELECT를 중첩하는 서브쿼리로 평균 초과 도서, 최다 주문 회원 등 조인으로 어려운 조건을 간결하게 표현합니다.

🎯 학습 목표

이 강을 마치면 쿼리 안에 또 다른 쿼리를 중첩하는 서브쿼리(Subquery)를 작성할 수 있습니다. WHERE 절의 IN 서브쿼리, 비교 연산 서브쿼리, FROM 절의 인라인 뷰, SELECT 절의 스칼라 서브쿼리를 각각 언제 어떻게 쓰는지 이해합니다. "평균 가격보다 비싼 도서", "가장 주문이 많은 회원"처럼 집계 결과를 조건으로 사용하는 강력한 쿼리를 작성할 수 있게 됩니다.

💡 서브쿼리란 무엇인가

이 섹션에서는 서브쿼리의 개념과 언제 조인 대신 서브쿼리를 선택하는지 살펴보겠습니다.

서브쿼리(Subquery)는 다른 SQL 문 안에 중첩된 SELECT 문입니다. 괄호 ()로 감싸며, 바깥 쿼리(외부 쿼리)가 실행되기 전에 먼저 실행됩니다. 서브쿼리의 결과는 외부 쿼리의 조건, 데이터 소스, 열 값으로 활용됩니다.

서브쿼리가 필요한 대표적인 상황은 "집계 결과를 조건으로 사용하고 싶을 때"입니다. 11강의 HAVING은 그룹 내 집계 결과를 필터링하지만, "전체 평균가격보다 비싼 도서"처럼 전체를 집계한 결과를 조건으로 쓰려면 서브쿼리가 필요합니다.

-- 평균 가격보다 비싼 도서 (서브쿼리 없이는 불가능)
SELECT title, price
FROM books
WHERE price > (SELECT AVG(price) FROM books)
ORDER BY price DESC;

괄호 안의 SELECT AVG(price) FROM books가 먼저 실행되어 평균 가격(예: 약 20,428원)을 반환합니다. 그 값을 외부 쿼리의 WHERE 조건에 사용합니다. 이처럼 서브쿼리를 쓰면 "먼저 계산하고, 그 결과로 다시 필터링"하는 2단계 처리를 하나의 쿼리로 표현할 수 있습니다.

🔢 스칼라 서브쿼리 — 단일 값 반환

이 섹션에서는 정확히 하나의 값만 반환하는 스칼라 서브쿼리를 살펴보겠습니다.

스칼라 서브쿼리(Scalar Subquery)는 결과가 반드시 1행 1열인 서브쿼리입니다. 단일 값(스칼라)을 반환하므로 비교 연산자(=, >, < 등)와 직접 결합할 수 있습니다.

-- 가장 비싼 도서와 같은 가격대(2만원 이상) 도서 조회
SELECT title, price,
       (SELECT MAX(price) FROM books) AS 최고가
FROM books
WHERE price >= 20000
ORDER BY price DESC;

SELECT 절에서 스칼라 서브쿼리를 사용하면 모든 행에 동일한 집계 값을 열로 추가할 수 있습니다. 위 예시에서 최고가 열에는 모든 행에 동일하게 33,000이 표시됩니다.

-- 전체 주문 건수에서 회원별 비율 계산
SELECT
  member_id,
  COUNT(*) AS 내주문수,
  (SELECT COUNT(*) FROM orders) AS 전체주문수,
  ROUND(COUNT(*) * 100.0 / (SELECT COUNT(*) FROM orders), 1) AS 비율퍼센트
FROM orders
GROUP BY member_id
ORDER BY 내주문수 DESC;

전체 주문 수를 스칼라 서브쿼리로 가져와 각 회원의 주문 비율을 계산합니다. 100.0을 곱해 정수 나눗셈이 되지 않도록 실수 나눗셈을 유도합니다.

스칼라 서브쿼리가 2개 이상의 행이나 열을 반환하면 오류가 발생합니다. 반드시 1행 1열임을 보장해야 합니다. COUNT(*), MAX(), MIN(), AVG(), SUM()처럼 집계 함수는 항상 1행을 반환하므로 스칼라 서브쿼리에 안전하게 쓸 수 있습니다.

📋 IN 서브쿼리 — 목록 조건

이 섹션에서는 서브쿼리 결과를 IN 조건의 목록으로 사용하는 방법을 살펴보겠습니다.

5강에서 배운 IN 연산자의 목록 자리에 서브쿼리를 넣을 수 있습니다. 서브쿼리가 여러 행을 반환하고, 그 값들 중 하나와 일치하는 행을 외부 쿼리에서 찾습니다.

-- 주문한 적 있는 회원의 상세 정보 조회
SELECT member_id, name, grade, email
FROM members
WHERE member_id IN (SELECT DISTINCT member_id FROM orders)
ORDER BY member_id;

서브쿼리가 먼저 실행되어 orders 테이블에 있는 고유한 member_id 목록(예: 1, 2, 3, 4, 5)을 반환합니다. 외부 쿼리는 그 목록에 포함된 회원만 가져옵니다. 결과는 13강의 INNER JOIN과 동일하지만, 서브쿼리 방식이 더 직관적으로 읽히는 경우가 있습니다.

-- IT 카테고리 도서를 주문한 적 있는 회원 이름 조회
SELECT name, grade
FROM members
WHERE member_id IN (
  SELECT DISTINCT o.member_id
  FROM orders AS o
  INNER JOIN books AS b ON o.book_id = b.book_id
  WHERE b.category = 'IT'
)
ORDER BY name;

서브쿼리 안에 JOIN을 포함할 수도 있습니다. IT 도서를 주문한 주문들의 member_id를 먼저 뽑고, 그 회원들의 정보를 외부 쿼리에서 가져옵니다.

NOT IN도 같은 방식으로 사용할 수 있습니다.

-- 한 번도 주문하지 않은 회원
SELECT name, grade
FROM members
WHERE member_id NOT IN (SELECT DISTINCT member_id FROM orders);

-- 주의: NOT IN의 서브쿼리에 NULL이 있으면 결과가 비어버림!
-- 안전한 방법: NOT EXISTS 또는 LEFT JOIN WHERE NULL 패턴

NOT IN을 쓸 때 서브쿼리 결과에 NULL이 포함되면 전체 결과가 비어버리는 함정이 있습니다. 서브쿼리 안에 WHERE member_id IS NOT NULL을 추가하거나, 14강의 LEFT JOIN WHERE NULL 패턴을 사용하는 것이 더 안전합니다.

📊 FROM 절 서브쿼리 — 인라인 뷰

이 섹션에서는 FROM 절에 서브쿼리를 넣어 임시 테이블처럼 활용하는 인라인 뷰(Inline View)를 살펴보겠습니다.

FROM 절의 서브쿼리는 "가상의 임시 테이블"처럼 동작합니다. 복잡한 집계나 조인 결과를 먼저 만들어 두고, 그 결과를 외부 쿼리에서 다시 조회하는 패턴입니다. 인라인 뷰(Inline View) 또는 파생 테이블(Derived Table)이라고 부릅니다.

-- 카테고리별 평균 가격을 구한 뒤, 전체 평균보다 높은 카테고리만 조회
SELECT *
FROM (
  SELECT
    category,
    COUNT(*)              AS 도서수,
    ROUND(AVG(price), 0)  AS 평균가격
  FROM books
  GROUP BY category
) AS 카테고리통계
WHERE 평균가격 > (SELECT ROUND(AVG(price), 0) FROM books)
ORDER BY 평균가격 DESC;

안쪽 서브쿼리가 먼저 카테고리별 통계를 만든 다음, 외부 WHERE에서 전체 평균보다 높은 카테고리만 남깁니다. FROM 절의 서브쿼리에는 반드시 별칭(AS 카테고리통계)을 붙여야 합니다.

이 패턴은 HAVING으로는 불가능한 "집계 결과를 다시 집계하거나 필터링"할 때 특히 유용합니다. 또한 서브쿼리에서 계산한 열(평균가격)을 외부 WHERE에서 별칭으로 사용할 수 있는 장점도 있습니다.

📝 핵심 요약

이번 강에서 배운 내용을 정리하겠습니다.

유형위치반환예시
스칼라 서브쿼리WHERE, SELECT1행 1열WHERE price > (SELECT AVG(price) FROM books)
IN 서브쿼리WHERE IN/NOT IN1열 N행WHERE id IN (SELECT id FROM ...)
인라인 뷰FROM 절N행 N열FROM (SELECT ... GROUP BY ...) AS t

서브쿼리는 복잡한 요구사항을 단계별로 분해해서 해결하는 도구입니다. 다음 17강에서는 두 쿼리의 결과를 합치거나 교집합·차집합을 구하는 집합 연산(UNION, INTERSECT, EXCEPT)을 배웁니다. 여러 조건의 결과를 하나로 합쳐야 할 때 JOIN이나 OR 대신 집합 연산이 더 명확한 표현이 됩니다.

관련 주제

  • 서브쿼리
  • IN 서브쿼리
  • 스칼라 서브쿼리
  • 인라인 뷰
  • WHERE 절 서브쿼리
  • 개발·프로그래밍
  • 개발·프로그래밍 강의
  • SQL·데이터베이스 입문 24강
  • 무료강의
  • 무료 온라인 강의
  • NUGUNA
  • 누구나

📚 시리즈 전체 공유

SQL·데이터베이스 입문 24강

이 강의가 속한 시리즈는 총 24강, 모두 무료입니다. 처음부터 배우려는 동료에게 시리즈 전체를 알려 주세요.

댓글

0/1000

불러오는 중...