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)와 함께 사용해야 한다.
- IN: 서브쿼리의 결과 중 하나라도 일치하는 값이 있으면 참(True)이 된다.
- 가장 자주 쓰이는 다중행 연산자.
- ANY / SOME: 서브쿼리의 결과 중 어느 하나라도 조건을 만족하면 참이 된다. (OR 조건과 유사)
- 주요 조합:
- > ANY (10, 20, 30) ➔ 최솟값(10)보다 크면 참 (10보다 크거나, 20보다 크거나, 30보다 크거나 즉, 10보다만 크면 됨)
- < ANY (10, 20, 30) ➔ 최댓값(30)보다 작으면 참
- = ANY는 IN과 완전히 같은 역할을 한다.
- 주요 조합:
- ALL: 서브쿼리의 결과 모든 값을 만족해야 참이 된다. (AND 조건과 유사)
- 주요 조합:
- > ALL (10, 20, 30) ➔ 최댓값(30)보다 커야 참 (10보다도 크고, 20보다도 크고, 30보다도 커야 하므로)
- < ALL (10, 20, 30) ➔ 최솟값(10)보다 작아야 참
- 주요 조합:
- EXISTS / NOT EXISTS: 서브쿼리의 결과가 존재하는지 여부만 따진다. 값이 있냐 없냐만 보기 때문에 실제 데이터를 비교하지 않음.
- 만족하는 행을 찾는 순간 탐색을 멈추기 때문에 대용량 데이터에서 성능상 유리할 때가 많다. 메인 쿼리의 테이블과 연결하는 '상호연관 서브쿼리' 형태로 주로 쓰인다.
- IN: 서브쿼리의 결과 중 하나라도 일치하는 값이 있으면 참(True)이 된다.
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);
'Language > sql' 카테고리의 다른 글
| 🗄️CASE문 문법 및 활용법 총정리 (Simple / Searched / SUM() 활용 / ORDER BY절에서의 사용) (0) | 2026.07.06 |
|---|---|
| 🗄️연관관계 매핑 전략과 핵심 개념(다대일, 일대다, 연관관계의 주인) (0) | 2026.07.02 |
| 🗄️주요 JOIN의 종류 완벽 정리(Inner, Left, Cross, Self 등) (0) | 2026.07.02 |
| 🗄️SQL 쿼리 작성 순서와 실행 순서 (0) | 2026.07.02 |