이제 토끼굴을 더 깊게 파보자! FROM 구문에서 서브쿼리를 어떻게 쓰는지 알아볼 거야. 이건 SQL 개발자들이 진짜 자주 쓰는 방법인데, 바로 그 자리에서 강력한 임시 테이블을 만들고, 마치 DB에 원래 있던 테이블처럼 재사용할 수 있거든.
예를 들어, 리포트를 만들어야 하는데 계산, 그룹핑, 필터링 같은 작업이 필요해. 근데 서버에 임시 테이블을 따로 만들고 싶진 않아. 그럴 땐? 바로 FROM에서 서브쿼리가 등장하지! 이걸로 할 수 있는 건:
- 데이터를 임시로 합치거나 집계해서 메인 쿼리 전에 준비할 수 있어.
- 즉석에서 구조화된 데이터셋을 만들 수 있어.
- DB에 중간 데이터를 최소한만 저장하게 해서, 작업을 더 간단하게 할 수 있어.
FROM에서의 서브쿼리는 미니 테이블처럼 동작해. 메인 쿼리에서 이걸 테이블처럼 쓸 수 있지. 약간 레고 조립하는 느낌이야: 빠르고, 유연하고, 쓸데없는 오버헤드도 없어 :)
FROM에서 서브쿼리의 기본
FROM에서 서브쿼리를 쓰면 임시 테이블(혹은 서브테이블)을 만들고, 이게 전체 쿼리의 일부가 돼. 이걸 하려면 세 가지 핵심 단계를 따라야 해:
- 서브쿼리를
FROM구문에 괄호로 감싸서 작성해. - 서브쿼리에 alias(별명)을 붙여.
- 그 별명을 마치 진짜 테이블처럼 써.
문법
SELECT 컬럼들
FROM (
SELECT 컬럼들
FROM 테이블
WHERE 조건
) AS 별명
WHERE 외부_조건;
좀 무섭게 느껴져? 예시로 바로 가보자.
예시: 학생들과 평균 점수
우리한테 두 개의 테이블이 있다고 해보자:
students (학생 정보 — 이름과 ID):
| student_id | student_name |
|---|---|
| 1 | Alex |
| 2 | Anna |
| 3 | Dan |
grades (학생들의 점수 데이터):
| grade_id | student_id | grade |
|---|---|---|
| 1 | 1 | 80 |
| 2 | 1 | 85 |
| 3 | 2 | 90 |
| 4 | 3 | 70 |
| 5 | 3 | 75 |
이제 미션: 학생 목록과 그들의 평균 점수를 구해보자.
먼저 각 학생의 평균 점수를 계산하는 간단한 서브쿼리부터 시작해서, 그걸 메인 쿼리에서 써보자.
SELECT s.student_name, g.avg_grade
FROM (
SELECT student_id, AVG(grade) AS avg_grade
FROM grades
GROUP BY student_id
) AS g
JOIN students AS s ON s.student_id = g.student_id;
결과:
| student_name | avg_grade |
|---|---|
| Alex | 82.5 |
| Anna | 90.0 |
| Dan | 72.5 |
즉석에서 만드는 임시 테이블
FROM에서의 서브쿼리는 데이터 처리를 여러 단계로 해야 할 때 특히 유용해. 예를 들어, 평균 점수뿐만 아니라 각 학생의 최고 점수도 한 번에 계산하고 싶을 때!
SELECT g.student_id, g.avg_grade, g.max_grade
FROM (
SELECT student_id,
AVG(grade) AS avg_grade,
MAX(grade) AS max_grade
FROM grades
GROUP BY student_id
) AS g;
결과:
| student_id | avg_grade | max_grade |
|---|---|---|
| 1 | 82.5 | 85 |
| 2 | 90 | 90 |
| 3 | 72.5 | 75 |
이렇게 하면 avg_grade와 max_grade라는 컬럼이 있는 진짜 임시 테이블처럼 쓸 수 있어.
FROM에서 서브쿼리를 언제 쓰면 좋을까?
집계 데이터가 필요할 때. 먼저 평균, 합계, 최대값 같은 계산을 하고, 그 결과를 다른 테이블과 조인하고 싶을 때.
데이터 필터링할 때. 메인 테이블과 합치기 전에 데이터를 미리 걸러내고 싶을 때.
복잡한 쿼리를 단순화할 때. 복잡한 작업을 단계별로 나누면 헷갈리지 않아.
예시: 두 단계로 처리하는 학생 리포트
이번엔 평균 점수가 80점 넘는 학생만 찾고 싶다고 해보자. 먼저 평균 점수를 계산하는 서브쿼리를 만들고, 그걸 필터에 써보자.
SELECT s.student_name, g.avg_grade
FROM students AS s
JOIN (
SELECT student_id, AVG(grade) AS avg_grade
FROM grades
GROUP BY student_id
) AS g ON s.student_id = g.student_id
WHERE g.avg_grade > 80;
결과:
| student_name | avg_grade |
|---|---|
| Alex | 82.5 |
| Anna | 90.0 |
사용 팁과 주의사항
별명은 꼭 붙이기. 서브쿼리에는 항상 alias(예: AS g)를 붙여야 해. 안 그러면 PostgreSQL이 이 "임시 테이블"을 어떻게 불러야 할지 몰라.
최적화. FROM에서의 서브쿼리는 테이블 조인(JOIN)보다 느릴 수 있어. 특히 서브쿼리 안에서 데이터를 필터링할 때 더 그래.
인덱스. 조인에 쓰는 컬럼, 인덱스, 필터가 잘 최적화되어 있는지 꼭 확인해. 이게 성능에 진짜 큰 영향을 줘.
복잡한 쿼리 예시: 강의와 학생 수
이제 좀 더 어려운 실제 문제를 풀어보자. 이런 테이블이 있다고 해보자:
courses (강의 목록):
| course_id | course_name |
|---|---|
| 1 | SQL Basics |
| 2 | Python Basics |
그리고 enrollments (학생들의 강의 수강 기록):
| student_id | course_id |
|---|---|
| 1 | 1 |
| 1 | 2 |
| 2 | 1 |
이제 각 강의에 몇 명의 학생이 등록했는지 알고 싶어.
SELECT c.course_name, e.students_count
FROM courses AS c
JOIN (
SELECT course_id, COUNT(student_id) AS students_count
FROM enrollments
GROUP BY course_id
) AS e ON c.course_id = e.course_id;
결과:
| course_name | students_count |
|---|---|
| SQL Basics | 2 |
| Python Basics | 1 |
강의가 재밌었길 바라! 다음 강의는 더 흥미로울 거야 :)
GO TO FULL VERSION