- 비상관 서브쿼리와 상관 서브쿼리
- 비상관 서브쿼리란 outer query와 독립적으로 실행 가능한 쿼리를 말합니다. 전체 쿼리에서 서브쿼리만 똑 떼다가 실행해도 잘 작동합니다.
- 상관 서브쿼리는 서브쿼리를 감싸는 outer query와 상관 관계가 있는 쿼리를 말합니다. 상관 서브쿼리는 outer query와 독립적으로 작동할 수 없습니다.
- 서브쿼리에 outer qeury의 table을 인용하는 경우에 상관 쿼리가 됩니다. 아래는 예시입니다.
SELECT * FROM user
WHERE EXISTS (SELECT * FROM invoice WHERE invoice.user_id = user.id)
- EXISTS는 뒤에 따라오는 조건이 참일 때 True를 반환합니다. 즉, 뒤의 서브쿼리가 참일 때마다 user 테이블에서 row가 하나씩 조회됩니다.
- 서브쿼리에서 user 테이블을 인용하고 있습니다. 인용되는 user 테이블은 서브쿼리의 바깥, 즉 outer query에 있습니다. 이때 서브쿼리는 outer qeury 없이 작동하지 않습니다.
- 서브쿼리의 의미는 다음과 같습니다. 'invoice 테이블에 있는 user_id의 값과 user 테이블에 있는 id의 값이 같은 invoice 테이블의 row를 출력하라'입니다.
- 한 문장으로 말하자면, user 중에서 주문 내역이 있는 user만 조회하겠다는 것입니다. 쿼리가 작동하는 순서를 정리해보겠습니다.
- user 테이블의 첫 번째 row를 불러옵니다.
- 그 row의 id(user.id)와 같은 값이 invoice의 user.id(invoice.user_id)에 있는지 조회합니다.
- 만약에 존재한다면, WHERE 절은 True가 되고, 첫 번째 row가 쿼리창에 결과로 나타날 수 있게 됩니다.
- 두 번째, 세 번째 row에 대해서 2~3번 과정을 반복합니다.
아래와 같이 SELF JOIN처럼 사용할 수 있습니다.
SELECT *,
(SELECT MIN(salary)
FROM employee AS e2 WHERE appointment_date IS NOT NULL
AND position IS NOT NULL
AND YEAR(e1.appointment_date) = YEAR(e2.appointment_date)) AS min_salary_in_the_year
FROM employee AS e1;
작동 원리는 이렇습니다.
- 일단 e1 테이블에서 첫 번째 row를 불러옵니다.
- 임명 날짜와 포지션이 누락되지 않은 직원을 대상으로 쿼리가 작동됩니다.
- (row를 하나씩 확인하는 EXISTS와 다릅니다) e1의 첫 번째 row의 임명연도와 같은 row들을 찾습니다.
- 3번에서 찾은 row들의 salary 최소값을 구합니다.
- 최소값을 e1 테이블의 맨 오른쪽 컬럼에 출력합니다.