목차
서브쿼리(Subquery)
서브쿼리는 말 그대로 메인이 아닌 보조(서브) 역할을 하는 쿼리를 뜻한다.
즉, 하나의 메인 SQL문 안에 포함되어 실행되는 SELECT 문을 말한다.
보통 메인 쿼리가 실행되기 전에
서브쿼리가 먼저 실행되어 그 결과가 조건, 조회 값, 테이블처럼 사용된다.
그래서 서브쿼리는 SELECT, FROM, WHERE, HAVING 절 등 다양한 위치에 들어갈 수 있다.
예를들어,
SELECT name
FROM students
WHERE score > (SELECT AVG(score) FROM students);
→ 이때 괄호 안의 SELECT AVG(score)... 부분이 바로 서브쿼리이다.
메인 쿼리는 이름을 가져오는 역할이고,
서브쿼리는 평균 점수를 구해서 메인 쿼리의 조건으로 사용되는 것이다.
✅ 서브쿼리의 종류
위치 | 서브쿼리 종류 | 설명 |
SELECT 절 | 스칼라 서브쿼리(Scalar Subquery) | 단일 값을 SELECT 절에서 조회할 때 사용 |
FROM 절 | 인라인 뷰(Inline View) | SELECT 결과를 테이블처럼 사용 |
WHERE/ HAVING 절 | 중첩 서브쿼리(Nested Subquery) | 조건절에서 결과를 비교하기 위해 사용 |
스칼라 서브쿼리(SELECT 절)
SELECT 안에 들어가서 단 하나의 값을 조회
→ 꼭 단일 값만 반환해야 함 (row 1, col 1)
📌 예제
SELECT name,
(SELECT MAX(score) FROM scores) AS max_score
FROM students;
✅ 모든 학생 행에 대해 최고 점수가 함께 표시됨
인라인 뷰(FROM 절)
FROM 안에 SELECT 문을 넣어서 가상의 테이블처럼 사용하는 것
📌 예제
SELECT name, avg_score
FROM (
SELECT student_id, AVG(score) AS avg_score
FROM scores
GROUP BY student_id
) AS avg_table
JOIN students ON avg_table.student_id = students.student_id;
✅ 학생별 평균 점수를 구한 결과를 FROM 안에서 테이블처럼 사용한 것
중첩 서브쿼리(WHERE/HAVING 절)
조건문 안에 들어가서 필터링 기준이 되는 쿼리
📌 예제
SELECT name
FROM students
WHERE student_id IN (
SELECT student_id1
FROM scores
WHERE subject = '수학'
);
✅ 수학 점수가 있는 학생만 조회됨 → 서브쿼리가 조건의 일부가 됨
✅ 중첩 서브쿼리 추가 팁
WHERE 절, HAVING 절 등 조건에 포함된 서브쿼리를 통틀어 중첩 서브쿼리(Nested Subquery)라고 한다.
이 중에서 메인쿼리와 독립적인지, 참조하는지에 따라 아래 두 가지로 나뉜다.
비연관 서브쿼리(Non-Correlated Subquery)
메인 쿼리와 독립적으로 한 번만 실행되는 서브쿼리
항목 | 설명 |
의존성 | 메인 쿼리와 전혀 관계 없음 |
실행 횟수 | 단 한 번 실행되고, 그 결과로 조건 판단 |
성능 | 일반적으로 빠름 |
주로 사용되는 곳 | IN, =, NOT IN, >=, ANY, ALL, HAVING, WHERE |
📌 예제
SELECT name
FROM students
WHERE score >= (
SELECT AVG(score) FROM students
);
- SELECT AVG(score)...는 한 번만 실행됨
- 메인 쿼리와 별개로 동작함 → 비연관 서브쿼리
연관 서브쿼리(Correlated Subquery)
서브쿼리 안에서 메인 쿼리의 값을 참조하는 서브쿼리
그냥 서브쿼리 내에 메인쿼리의 컬럼이 존재하면 연관 서브 쿼리이다. 비연관 서브쿼리는 그 반대이다.
항목 | 설명 |
의존성 | 서브 쿼리가 메인쿼리의 값을 참조함 |
실행 횟수 | 메인 쿼리의 행 수만큼 반복 실행됨 |
성능 | 느릴 수 있음(행마다 반복하기에) |
주로 사용되는 곳 | 행마다 조건을 다르게 줄 때, 조건이 복잡할 때 |
📌 예제
SELECT s1.name
FROM students s1
WHERE score > (
SELECT AVG(score)
FROM students s2
WHERE s2.class_id = s1.class_id
);
- s1.class_id를 서브쿼리에서 사용하고 있음 → 연관 서브쿼리
- 각 행마다 다른 조건으로 비교됨
✅ 실무 팁
- 연관 서브쿼리는 성능상 부담이 될 수 있으므로, JOIN으로 바꾸는 게 더 효율적일 때도 많음.
- 하지만 조건이 매우 동적인 경우에는 연관 서브쿼리가 더 자연스럽게 표현됨.
🧠 한 줄 정리
비연관 서브쿼리는 독립적으로 한 번만 실행되는 조건용 쿼리,
연관 서브쿼리는 메인 쿼리의 각 행과 연결되어 반복적으로 실행되는 동적 쿼리다.
단일 행 , 다중 행, 다중 컬럼 서브쿼리
서브쿼리를 **결과 형태(반환 값)**에 따라 분류하는
✅ 단일 행 서브쿼리
✅ 다중 행 서브쿼리
✅ 다중 컬럼 서브쿼리
이 개념은 서브쿼리의 비교 연산자 선택, 오류 방지, 문법 설계에 아주 중요하다.
결과가 1행 1열인 서브쿼리
✅ 예제
SELECT name
FROM students
WHERE score > (
SELECT AVG(score)
FROM students
);
- AVG(score)는 1개의 숫자 → 단일 값
- 비교 연산자: =, >, < 등 사용 가능
❗ 에러 예시
SELECT name
FROM students
WHERE score = (
SELECT score
FROM scores
WHERE subject = '수학'
);
→ 수학 과목 점수가 여러 개 있으면 "서브쿼리에서 둘 이상의 행을 반환했습니다" 오류 발생!
2️⃣ 다중 행 서브쿼리 (Multi-Row Subquery)
**결과가 여러 행(1열)**인 서브쿼리
✅ 예제
SELECT name
FROM students
WHERE student_id IN (
SELECT student_id1
FROM scores
WHERE subject = '수학'
);
- IN, ANY, ALL, EXISTS 같은 연산자가 필요함
IN | 여러 값 중 하나와 일치 |
ANY | 서브쿼리 결과 중 하나라도 만족 |
ALL | 서브쿼리 결과 모두를 만족해야 함 |
-- ANY 예시
SELECT name
FROM students
WHERE score > ANY (
SELECT score FROM scores WHERE subject = '영어'
);
-- ALL 예시
SELECT name
FROM students
WHERE score > ALL (
SELECT score FROM scores WHERE subject = '과학'
);
3️⃣ 다중 컬럼 서브쿼리 (Multi-Column Subquery)
**서브쿼리 결과가 여러 열(2열 이상)**인 경우
✅ 예제
SELECT name
FROM students
WHERE (student_id, class_id) IN (
SELECT student_id, class_id
FROM enrollments
);
- 두 개의 컬럼을 동시에 비교해야 할 때 유용
- 주로 (A, B) IN (SELECT A, B ...) 형태로 사용
🧠 정리 한줄
서브쿼리를 사용할 땐 "무엇을 반환하느냐"가 가장 중요하다.
단일 값이면 =, 여러 값이면 IN, 여러 컬럼이면 (a,b) IN (...)처럼
형태에 맞는 연산자를 반드시 사용해야 오류 없이 정확한 쿼리를 만들 수 있다.
✅ 서브쿼리 위치 총정리 표
위치(절) | 서브쿼리 종류 | 설명 |
SELECT | 스칼라 서브쿼리 | SELECT 결과에 단일 값을 컬럼처럼 포함 |
ORDER BY | 스칼라 서브쿼리 | 정렬 기준으로 단일 값을 넣을 수 있음 |
FROM | 인라인 뷰 | SELECT 결과를 테이블처럼 사용 |
WHERE | 중첩 서브쿼리 | 조건 판단용. IN, =, EXISTS, ANY, ALL 등과 함께 |
HAVING | 중첩 서브쿼리 | 그룹 조건 판단용 |
UPDATE - SET 절 | 스칼라 서브쿼리 | 특정 컬럼을 서브쿼리 결과값으로 갱신 |
UPDATE - WHERE 절 | 중첩 서브쿼리 | 어떤 행을 업데이트할지 조건으로 사용 |
DELETE - WHERE 절 | 중첩 서브쿼리 | 삭제 조건 지정 |
INSERT - VALUES 절 | 스칼라 서브쿼리 | 삽입 값으로 서브쿼리 결과 사용 |
INSERT - SELECT | 인라인 뷰 | FROM 안에 서브쿼리로 가져와 INSERT |
MERGE 절 (Oracle 등) | 다양함 | 조건 비교 및 값 설정 시 서브쿼리 사용d |
'SQL > SQLD' 카테고리의 다른 글
#17 집합 연산자 (0) | 2025.04.14 |
---|---|
#16 뷰(View) (0) | 2025.04.14 |
#14 JOIN (0) | 2025.04.13 |
#13 ORDER BY (0) | 2025.04.13 |
#12 GROUP BY, HAVING 절 (0) | 2025.04.13 |