서브쿼리란 다른 쿼리 내부에 포함되어 있는 SELECT 문을 의미
예제) 주소가 서울인 고객이 예약한 예약 정보만을 선택
SELECT ID, ReserveDate, RoomNum
FROM Reservation
WHERE Name IN **(SELECT Name
FROM Customer
WHERE Address = '서울'
)
SELECT FROM WHERE HAVING ORDER BY INSERT 문의 VALUES UPDATE 문의 SET 에서 사용 가능
비교 연산자와 함께 사용 → < > = IN NOT IN EXIST NOT EXIST
괄호를 감싸서 사용
서브쿼리 내 ORDER BY 사용 불가
단일 행 서브쿼리
서브쿼리가 단일 행 비교 연산자와 함께 사용할 때
SELECT name, age
FROM users
WHERE name = (SELECT name
FROM posts
WHERE post_id = 1);
⚠️ 서브쿼리의 결과는 무조건 1개 이하여야 함
단일 행 비교 연산자
| 연산자 | 의미 |
|---|---|
| > | 큼 |
| < | 작음 |
| ≥ | 크거나 같음 |
| ≤ | 작거나 같음 |
| = | 같음 |
| ! = , <>, ^= | 같지 않음 |
다중 행 서브쿼리
서브쿼리가 다중 행 비교 연산자와 함께 사용할 때
SELECT name, age
FROM users
WHERE name IN (SELECT name
FROM posts
WHERE post_id > 2);
⚠️ 서브쿼리의 결과가 2개 이상일 때 사용
| 연산자 | 사용법 | 의미 |
|---|---|---|
| IN | (M) IN (S) | 서브쿼리의 결과 중에 하나라도 만족하는 것 |
| ANY, SOME | (M) = ANY/SOME (S) | 서브쿼리의 결과 중에 하나라도 만족하는 것 |
| ANY, SOME | (M) < ANY/SOME (S) | 서브쿼리의 결과 중 최댓값 보다 작은 것 |
| ANY, SOME | (M) > ANY/SOME (S) | 서브쿼리의 결과 중 최솟값 보다 큰 것 |
| ALL | (M) < ALL (S) | 서브쿼리의 결과 중 최솟값 보다 작은 것 |
| ALL | (M) > ALL (S) | 서브쿼리의 결과 중 최댓값 보다 큰 것 |
| EXISTS | (M) EXISTS (S) | 서브쿼리의 결과 중에 하나라도 만족하는 것 |
다중 컬럼 서브쿼리
서브쿼리 결과가 다중 칼럼이고 메인쿼리의 조건과 동시에 비교할 때
SELECT name, image, age
FROM users
WHERE (name, image) IN (SELECT name, image
FROM posts
WHERE post_id = 3);
⚠️ name과 image는 users와 posts에 모두 존재하는 컬럼
연관 서브쿼리
서브쿼리 내에 메인쿼리 컬럼 사용
SELECT users.user_id, users.name, users.image
FROM users as users
WHERE (users.user_id, users.name) IN (SELECT posts.user_id, posts.name
FROM posts as posts
WHERE posts.name = users.name);
서브쿼리가 한 행, 한 컬럼만을 반환할 때 사용
SELECT users.age, (SELECT AVG(enrolls.age) FROM enrolls as enrolls)
FROM users as users;
users 테이블
| id | name | age |
|---|---|---|
| 1 | Alice | 25 |
| 2 | Bob | 30 |
| 3 | Charlie | 22 |
enrolls 테이블
| id | user_id | age |
|---|---|---|
| 1 | 1 | 25 |
| 2 | 2 | 30 |
| 3 | 3 | 22 |
| 4 | 4 | 27 |
결과
| age | AVG(enrolls.age) |
|---|---|
| 25 | 26 |
| 30 | 26 |
| 22 | 26 |
동적으로 조인 방식을 사용하는 것과 같음
SELECT users.id, enrolls.user_id, enrolls.course_id
FROM users,
(SELECT user_id, course_id FROM enrolls) enrolls
WHERE users.id = enrolls.user_id;
users 테이블
| id | name | age |
|---|---|---|
| 1 | Alice | 25 |
| 2 | Bob | 30 |
| 3 | Charlie | 22 |
enrolls 테이블
| id | user_id | course_id |
|---|---|---|
| 1 | 1 | 101 |
| 2 | 2 | 102 |
| 3 | 3 | 103 |
| 4 | 1 | 104 |
결과
| id | user_id | course_id |
|---|---|---|
| 1 | 1 | 101 |
| 1 | 1 | 104 |
| 2 | 2 | 102 |
| 3 | 3 | 103 |
서브쿼리 : 생존기간(스코프)이 SQL 구문 실행 중으로 한정
장점
기능적으로 유연
조인과 관련된 쿼리에서 서브쿼리가 더 나은 경우가 존재
→ 테이블을 조인할 때 조인 대상 레코드 수를 최대한 줄이는 것이 중요하나 옵티마이저가 제대로 판단하지 못할 때 사용자가 서브쿼리로 직접 연산 순서를 명시해줌으로써 성능적으로 좋을 수 있음
단점
테이블에 비해 성능이 떨어짐 → 서브 쿼리가 데이터의 실체를 저장하지 않고 있기 때문
→ 내부적으로 복잡한 연산을 수행하거나 결과 크기가 큰 서브 쿼리를 사용할 때는 성능 리스크를 고려해야함
참고자료