본문 바로가기
Language/sql

🗄️서브쿼리 개념 종류 및 JOIN과의 차이점 완벽 정리

by 박수무당벌레 2026. 7. 2.

1. 서브쿼리(Subquery)란?

  • 서브쿼리는 말 그대로 하나의 SQL 쿼리 안에 또 다른 SQL 쿼리가 포함되어 있는 형태를 말한다. (쿼리 안의 쿼리)
    • 메인이 되는 바깥쪽 쿼리를 메인 쿼리(Main Query)라고 하고, 안쪽에 포함된 쿼리를 서브쿼리라고 부름.
  • 메인 쿼리가 실행되기 위해 필요한 데이터를 중간에서 계산하거나 필터링해주는 역할을 한다.
  • SQL 문 내의 거의 모든 곳(SELECT, FROM, WHERE 등)에 위치할 수 있으며, 어디에 쓰이느냐/데이터 반환 형태에 따라 분류된다.

2. 서브쿼리가 사용되는 위치에 따른 분류

① 스칼라 서브쿼리 (Scalar Subquery) — SELECT 절에 사용

  • 특징: 반드시 단 하나의 행과 하나의 컬럼(1행 1열, 단일값)만 반환해야 한다.
  • 용도: 데이터의 결과 컬럼 옆에 다른 테이블의 가공된 값을 붙이고 싶을 때 사용한다.
SELECT user_id, 
       (SELECT COUNT(*) FROM Orders O WHERE O.user_id = U.user_id) AS order_count
FROM Users U;
-- 회원 목록을 조회하면서, 각 회원의 총 주문 횟수를 옆에 붙여 출력

② 인라인 뷰 (Inline View) — FROM 절에 사용

  • 특징: 서브쿼리의 결과가 하나의 가상 테이블처럼 작동한다.
  • 용도: 원래 테이블의 데이터를 먼저 그룹화하거나 필터링한 '정제된 판판한 데이터'를 베이스로 삼아 다시 쿼리를 던지고 싶을 때 사용한다. (반드시 별칭(AS)을 지정 필수)
SELECT AVG(total_price) 
FROM (
    SELECT user_id, SUM(price) AS total_price 
    FROM Orders 
    GROUP BY user_id
) AS UserTotals;
-- 회원별 총 구매액을 먼저 구한 뒤(인라인 뷰), 그 결과들의 '평균'을 구함

③ 중첩 서브쿼리 (Nested Subquery) — WHERE / HAVING 절에 사용

  • 특징: 메인 쿼리의 조건식 안에서 값을 동적으로 결정할 때 사용한다.
  • 용도: 특정 조건을 만족하는 대상의 데이터만 필터링할 때 아주 자주 쓰임.
SELECT * FROM Users
WHERE user_id IN (SELECT user_id FROM Orders WHERE price >= 100000);
-- 10만 원 이상 주문한 적이 있는 회원들의 정보만 조회

3. 반환하는 데이터 형태에 따른 분류

  • 단일행 서브쿼리 (Single-Row Subquery): 결과가 딱 1건만 나오는 서브쿼리. 비교 연산자(=, >, <, !=)와 함께 사용한다.
    • 예: 평균 급여(AVG(salary))보다 많이 받는 사원 조회
  • 다중행 서브쿼리 (Multiple-Row Subquery): 결과가 여러 행으로 나오는 서브쿼리. 일반 비교 연산자는 사용할 수 없고, 다중행 연산자(IN, ANY, ALL, EXISTS)와 함께 사용해야 한다.
    1. IN: 서브쿼리의 결과 중 하나라도 일치하는 값이 있으면 참(True)이 된다.
      • 가장 자주 쓰이는 다중행 연산자.
    2. ANY / SOME: 서브쿼리의 결과 중 어느 하나라도 조건을 만족하면 참이 된다. (OR 조건과 유사)
      • 주요 조합:
        • > ANY (10, 20, 30) ➔ 최솟값(10)보다 크면 참 (10보다 크거나, 20보다 크거나, 30보다 크거나 즉, 10보다만 크면 됨)
        • < ANY (10, 20, 30) 최댓값(30)보다 작으면 
        • = ANY는 IN과 완전히 같은 역할을 한다.
    3. ALL: 서브쿼리의 결과 모든 값을 만족해야 참이 된다. (AND 조건과 유사)
      • 주요 조합:
        • > ALL (10, 20, 30)최댓값(30)보다 커야 참 (10보다도 크고, 20보다도 크고, 30보다도 커야 하므로)
        • < ALL (10, 20, 30) 최솟값(10)보다 작아야 
    4. EXISTS / NOT EXISTS: 서브쿼리의 결과가 존재하는지 여부만 따진다. 값이 있냐 없냐만 보기 때문에 실제 데이터를 비교하지 않음.
      • 만족하는 행을 찾는 순간 탐색을 멈추기 때문에 대용량 데이터에서 성능상 유리할 때가 많다. 메인 쿼리의 테이블과 연결하는 '상호연관 서브쿼리' 형태로 주로 쓰인다.

4. JOIN vs 서브쿼리 핵심 차이점

SQL에서 여러 테이블의 데이터를 결합하거나 조건에 맞는 데이터를 필드에 가져올 때 JOIN 서브쿼리를 가장 많이 사용한다.

많은 경우 서브쿼리로 작성한 코드는 JOIN 문으로 똑같이 구현할 수 있음.

두 방식은 최종적으로 같은 결과를 만들어낼 수 있지만, 작동 방식과 성능(데이터 처리 방식)에서 뚜렷한 차이가 있다.

무엇을 선택해야 할까? (선택 기준)

  • JOIN을 써야 할 때:
    • 조회하고자 하는 최종 결과물에 두 개 이상 복수 테이블의 컬럼들을 화면에 결합해 동시에 보여야 할 때 필수적.
    • 대용량 데이터를 처리하며, DBMS의 Optimizer가 인덱스를 활용해 최적화된 성능(Loop, Hash, Merge 등)을 내야 할 때 유리하다.
      • 대용량 데이터를 처리할 때 데이터베이스 엔진이 내부적으로 최적화(Tuning)하기 좋다.
      • 대개 JOIN이 서브쿼리보다 성능상 유리
  • 서브쿼리를 써야 할 때:
    • 다른 테이블의 데이터는 단순히 조건 필터링(존재 여부 확인 등)용으로만 쓰고, 결과에는 오직 메인 테이블의 컬럼만 노출할 때 좋다. (서브쿼리(WHERE절) 사용)
    • 복잡한 연산 결과를 단계별로 나누어 쿼리의 가독성을 높이고 싶을 때 유용하다. (최신 DBMS는 서브쿼리를 JOIN 형태로 알아서 변환하여 최적화(Subquery Unnesting)해주기도 하지만, 복잡한 서브쿼리는 여전히 성능 저하의 원인이 될 수 있다.)

📊 JOIN vs 서브쿼리 비교 요약

  JOIN 서브쿼리 (Subquery)
개념 여러 테이블을 하나의 집합으로 결합하여 조회 쿼리 내부에 또 다른 쿼리(하위 쿼리)를 포함하여 조회
결과 테이블 참여한 테이블의 컬럼을 동시에 모두 활용 가능 메인 쿼리 구조에 종속적 (주로 하나의 컬럼/값 제공)
가독성 테이블이 많아지면 쿼리가 다소 복잡해질 수 있음 쿼리가 단계별로 나누어져 있어 비교적 직관적
성능 (일반적) 인덱스를 타고 한 번에 결합하므로 대용량 데이터에 유리 데이터가 많을 경우 반복 연산 등으로 인해 성능이 저하될 수 있음
더보기

💡 작동 방식과 예시의 차이

 

상황 예시: 고객(Customers) 테이블과 주문(Orders) 테이블이 있을 때, 주문 기록이 있는 고객의 이름을 조회하는 경우 

 

1) JOIN 방식

  • JOIN은 두 테이블을 가로로 이어 붙여 하나의 커다란 테이블로 만든 뒤 데이터를 필터링한다.
  • 특징: Customers의 정보와 Orders의 정보를 SELECT 절에서 모두 자유롭게 꺼내 쓸 수 있습니다.
SELECT DISTINCT c.customer_name
FROM Customers c
INNER JOIN Orders o ON c.customer_id = o.customer_id;

 

2) 서브쿼리 방식

  • 서브쿼리는 하위 쿼리(안쪽 쿼리)를 먼저 실행하여 결과 조건을 만들고, 그 조건을 바탕으로 메인 쿼리(바깥쪽 쿼리)를 실행한다.
  • 특징: Orders 테이블의 데이터를 조건으로만 사용(서브쿼리 내부)할 뿐, 최종 SELECT 절에서는 Orders 테이블의 상세 컬럼(예: 주문일자, 주문금액 등)을 가져올 수 없다.
SELECT customer_name
FROM Customers
WHERE customer_id IN (SELECT customer_id FROM Orders);