이제 다음 단계로 넘어갈 준비가 됐어 — 바로 서브쿼리를 SQL에서 다루는 거야. 오늘은 서브쿼리가 뭔지, 왜 필요한지, 서브쿼리의 종류에는 뭐가 있는지, 그리고 실제로 왜 유용한지 알아볼 거야.
서브쿼리(또는 하위쿼리)는 다른 SQL 쿼리 안에서 사용하는 SQL 쿼리야. 약간 마트료시카나 양배추 같은 느낌이지: 바깥에 메인 쿼리가 있고, 그 안에 더 작은 쿼리가 숨어있어. 서브쿼리가 먼저 실행되고, 그 결과를 바깥 쿼리(가끔 "메인"이라고도 해)를 사용할 수 있어.
예시로 알아보자:
예시 1: 어떻게 동작하는지
우리에겐 students 테이블이 있고, 데이터는 다음과 같아:
| id | 이름 | 나이 | 그룹_id |
|---|---|---|---|
| 1 | 알리사 | 20 | 1 |
| 2 | 보브 | 22 | 2 |
| 3 | 클라크 | 21 | 1 |
| 4 | 디나 | 23 | 3 |
| 5 | 에밀리아 | 22 | 2 |
그리고 groups 테이블도 있는데, 여기엔 그룹 이름 정보가 들어있어:
| id | 이름 |
|---|---|
| 1 | 수학반 |
| 2 | 물리반 |
| 3 | 문학반 |
학생들이 속한 그룹의 이름을 알고 싶으면, 서브쿼리를 이렇게 쓸 수 있어:
SELECT 이름
FROM groups
WHERE id IN (
SELECT 그룹_id
FROM students
WHERE 나이 > 21
);
여기서 무슨 일이 일어나고 있을까?
서브쿼리:
SELECT 그룹_id
FROM students
WHERE 나이 > 21
이 쿼리는 나이가 21살 넘는 학생들의 그룹_id를 뽑아와. 결과는 그룹 id 리스트, 예를 들면 [2, 3]이야.
메인 쿼리:
SELECT 이름
FROM groups
WHERE id IN ([서브쿼리 결과])
이 쿼리는 서브쿼리 결과를 사용해서 id가 2나 3인 그룹의 이름을 반환해.
결과:
물리반
문학반
아직도 잘 모르겠어? 당연하지. 근데 걱정하지 마, 이제 하나씩 풀어볼 거야.
간단한 아이디어부터 시작하자 — SELECT 쿼리의 결과는 일종의 가상 테이블이야. 진짜로, 컬럼도 있고, 행도 있어. 그냥 테이블이지 뭐?
그리고 쿼리 결과가 테이블이라면, 실제 테이블 쓰는 곳(예를 들어 JOIN 연산자나 더 복잡한 구문)에서도 쓸 수 있어.
이름이 없는 게 문제긴 한데, 컬럼 표현식도 이름이 없으면 alias(별명) 붙여서 해결하잖아. 가상 테이블도 똑같이 별명 붙이면 돼.
이건 다음 강의에서 더 자세히 다룰 거야 — 스포는 여기까지 :P
서브쿼리의 장점
복잡한 문제를 쉽게 풀 수 있어. 한 테이블에 원하는 모든 정보가 없을 때가 있잖아? 서브쿼리를 쓰면 쿼리를 두 단계로 나눌 수 있어: 먼저 중간 결과를 찾고, 그걸로 최종 데이터를 뽑는 거지.
중간 결과를 다룰 수 있어. 서브쿼리는 데이터를 처리하기 전에 추가 계산이 필요할 때 유용해. 예를 들어 최소값을 찾거나 합계를 구할 때 말이야.
코드 가독성이 좋아져. 서브쿼리를 쓰면 코드가 더 구조적으로 보이고, 특히 큰 테이블이나 복잡한 로직을 다룰 때 좋아.
서브쿼리의 주요 타입
서브쿼리는 SQL 쿼리의 여러 부분에서 쓸 수 있어. 어디에 쓰느냐에 따라 몇 가지 타입으로 나뉘지.
SELECT안의 서브쿼리. 컬럼 리스트에 서브쿼리가 들어가서 값을 계산하는 데 써. 예를 들어 결과에 새로운 컬럼을 추가할 때 편해.
예시 — 학생들 중에서 최대 나이 컬럼을 추가해보자:
SELECT 이름, 나이,
(SELECT MAX(나이) FROM students) AS 최대_나이
FROM students;
결과:
| 이름 | 나이 | 최대_나이 |
|---|---|---|
| 알리사 | 20 | 23 |
| 보브 | 22 | 23 |
| 클라크 | 21 | 23 |
| 디나 | 23 | 23 |
| 에밀리아 | 22 | 23 |
FROM안의 서브쿼리. 서브쿼리를 임시 테이블처럼 써. 먼저 데이터를 집계하거나 변환해야 할 때 유용해.
예시 — 각 그룹별 학생 평균 나이 구하기:
SELECT tmp.그룹_id, tmp.평균_나이
FROM (
SELECT 그룹_id, AVG(나이) AS 평균_나이
FROM students
GROUP BY 그룹_id
) AS tmp -- 임시 테이블에 tmp라는 별명 붙임
WHERE tmp.평균_나이 > 21;
결과:
| 그룹_id | 평균_나이 |
|---|---|
| 2 | 22.0 |
| 3 | 23.0 |
WHERE와HAVING안의 서브쿼리. 서브쿼리가 조건이 돼서 행을 필터링해. 이건 주로- 레코드 존재 여부나 값 비교할 때 자주 써.
예시 — 평균 나이보다 많은 학생들 찾기:
SELECT 이름, 나이
FROM students
WHERE 나이 > (
SELECT AVG(나이)
FROM students
);
결과:
| 이름 | 나이 |
|---|---|
| 보브 | 22 |
| 디나 | 23 |
| 에밀리아 | 22 |
서브쿼리의 장점 정리
유연성 증가: 서브쿼리를 쓰면 더 복잡한 데이터 구조도 다룰 수 있어.
단계별로 문제 해결: 로직을 서브쿼리로 나누면 코드가 더 읽기 쉬워져.
중간 데이터 접근: 데이터베이스에 임시 테이블을 만들지 않아도, "실시간"으로 데이터를 처리할 수 있어.
GO TO FULL VERSION