오늘은 2과목 2장의 첫 내용, 서브쿼리를 다뤄보겠다.
서브쿼리
서브쿼리는 하나의 SQL문 안에 포함되어있는 또 다른 SQL문이다. 단독 쿼리문 만으로는 해결할 수 없는 검색을 수행시 활용한다.

이런식으로 서브쿼리가 메인쿼리보다 먼저 수행되며, 그 결과에 대해서 메인 쿼리를 수행한다!
서브쿼리를 사용할때는, 고려해야될 사항이 있다.
서브쿼리 사용시 고려사항
- 서브쿼리는 반드시 괄호에 감싸서 수행한다
- 서브쿼리는 비교 연산자의 우측에 위치한다
- TOP-N 분석 기능을 제외하거는 서브쿼리에 ORDER BY절을 수행할 필요가 없다.
- 결과값이 하나인 단일행 서브쿼리에 대해서는 단일행 연산자를, 결과값이 여러개인 다중행 서브쿼리에 대해서는 다중행 연산자를 사용한다.
여기서 단일행 서브쿼리, 다중행 서브쿼리가 나온다. 이렇게 서브쿼리에도 또 종류가 있다! 분류 기준을 통해 서브쿼리의 종류에 대해 알아보자.
우선, 반환 형태에 따라서 분류를 할 수 있다.
단일행 서브쿼리
단일행 서브쿼리는 결과값이 하나인 서브쿼리이다. 오직 하나의 행만 반환하므로, 단일행 비교연산자와 함께 작성된다.
단순하게 예시를 봐보자.
WHERE department_id = ( SELECT department_id FROM employees WHERE employee_id = 101 );
요런식으로 단일행 반환한다~
WHERE salary = ( SELECT MAX(salary) FROM emp );
이렇게 그룹함수를 쓸 수도 있다
GROUP BY department_id
HAVING min(salary) > ( SELECT MIN(salary) FROM emp WHERE departmend_id = 60);
요런식으로 HAVING 절에서도 응용 한다~~
단일행 서브쿼리에는 단일행 단일컬럼 서브쿼리, 단일행 다중컬럼 서브쿼리가 있다.
- 단일행 단일컬럼 : 1행 1열로 결과값이 스칼라이다.
- 단일행 다중컬럼 : 1행 N열로 여러컬럼을 한번에 비교할 때 사용된다. 다중컬럼은 비교할 때, 비교하고자 하는 컬럼개수와 컬럼의 위치가 동일해야된다!
다중행 서브쿼리
다중행 서브쿼리는 결과값이 여러개의 행이다. 여러가지 값을 반환하므로 IN, ANY, ALL, EXISTS와 같은 다중행 비교 연산자와 함께 사용해야한다. = 을 사용하면 오류가 발생한다!
다중행 비교연산자에는 아래와 같은 것들이 있다.

예시를 봐보자. 그러면서 다중행 비교 연산자도 설명을 좀 하겠다.
WHERE salary IN (SELECT MAX(salary) FROM emp GROUP BY department_id);
이렇게 서브쿼리에서 400,900,600이 나왔다 치자. 그러면, salary가 이 목록에있는 어느 값이랑도 같은지를 확인한다!
WHERE salary < ANY (SELECT salary FROM emp WHERE job_id = 'IT_PROG');
이렇게 하면, 서브쿼리에선 job_id가 IT_PROG인 레코드의 salary들이 나올텐데 그 중의 최대값보다 작은지를 본다! 어느 하나의 값보다도 작은 값이 있으면 되는 거다! 이런식으로 > ANY는 어느 하나의 값보다도 큰값이 있는지를 본다. 어느 하나의 값이라도!! 를 검사하는게 ANY이다.
WHERE salary < ALL (SELECT salary FROM emp WHERE job_id = 'IT_PROG');
이렇게하면, 서브쿼리에선 여러 값들이 나올거다. 예상했다시피 ALL은 이 값들 모두보다도 즉 최소값보다 작은지를 보는거다!
만약 서브쿼리의 결과값이 NULL인 경우에는 메인쿼리의 결과도 NULL을 반환한다.
⭐️⭐️⭐️
이번에는 서브쿼리를 사용 위치에 따라 분류할 수도 있다. 이게 더 중요하다고 한다!!
스칼라 서브쿼리
스칼라 서브쿼리의 사용위치는 SELECT 절이다. SELECT 목록에 컬럼처럼 사용되며, 반드시 단일행 단일컬럼만을 반환해야된다! 단일행 단일컬럼이면 스칼라값이므로 이름이 스칼라 서브쿼리인 거 같다.
SELECT
e.emp_name,
(SELECT d.dept_name FROM departments d WHERE d.department_id = e.department_id) AS department_name
FROM
employees e;
요런식으로 단일 값을 SELECT절의 컬럼으로 두는 애를 스칼라 서브쿼리라고 한다.
인라인 뷰
인라인 뷰는 FROM절에서 사용된다. 서브쿼리가 마치 하나의 가상 테이블(View)처럼 동작한다. 보통 별칭을 부여하며, 다중행 다중컬럼을 반환한다. View가 뭔지는 아주 초반 포스팅에서 다뤘다! 기억이 안난다면 다시 보러가자(실은 나도 기억 잘 안남 ㅜㅜ)
SELECT
e.emp_name,
d_avg.avg_sal
FROM
employees e,
(SELECT department_id, AVG(salary) AS avg_sal
FROM employees
GROUP BY department_id) d_avg
WHERE
e.department_id = d_avg.department_id;
여길 보면, FROM절 내에서 서브쿼리를 통해 새로운 가상테이블을 만드는 것을 볼 수 있다! 이게 인라인 뷰이다.
중첩 서브쿼리
중첩 서브쿼리는 WHERE절 또는 HAVING절에서 사용된다. 가장 일반적인 형태로, 위에 단일행 다중행 볼 때가 다 이 중첩 서브쿼리이다. 즉 조건절에서 비교값으로 사용된다! 위에 예시는 많았으니 얜 예시 코드를 안들겠다.
동작 방식에 따른 분류로도 나눌 수 있다.
비연관 서브쿼리(Non-Correlated Subquery)
얘는 메인 쿼리에 값을 전달하기 전에, 서브쿼리가 독립적으로 한 번만 실행되는 방식이다. 메인쿼리는 서브쿼리가 반환한 고정된 결과값을 받아서 작업을 수행한다. 독립적이기에, 서브쿼리 부분만 뗴어내서 실행해도 결과가 잘 나온다!
SELECT emp_name, salary
FROM employees
WHERE salary > (SELECT AVG(salary) FROM employees);
이 서브쿼리는 얘만 떼어내서 실행해도, employees에서 salary의 평균만 반환하기때문에 결과가 잘 나온다. 그리고 이거 한번만 실행돼서, 결과값이 고정되어있다!
연관 서브쿼리(Correlated Subquery)
연관 서브쿼리는, 서브쿼리가 독립적으로 실행될 수 없으며 메인쿼리가 각 행을 처리할때마다 서브쿼리도 반복적으로 실행된다. 메인쿼리의 컬럼값을 서브쿼리가 받아서 처리하고, 그리고 다시 메인쿼리에 전달하고, 메인쿼리의 다음 컬럼값을 또 서브쿼리가 처리하고... 이런방식이다.
SELECT emp_name, salary
FROM employees e1
WHERE salary > (SELECT AVG(salary)
FROM employees e2
WHERE e2.department_id = e1.department_id);
이 코드를 봐보면, 서브쿼리는 e1 테이블의 컬럼값을 조건절에서 사용중이다. 그렇기에, 서브쿼리만 띠어낸다면 무조건 동작을 안할 것이다! 그리고 e1에 있는 레코드 하나를 메인쿼리가 주면 서브쿼리가 받아서 조건절 수행하고 select하고, 그리고 다음 레코드를 메인쿼리가 서브쿼리에게 주고.. 이걸 반복하게 된다. 이것이 연관 서브쿼리이다!
이렇게 서브쿼리에 대해 알아보았다. 실은 쿼리문자체를 우리는 알고있기때문에, 크게 어려운 내용은 아니었던 거 같다!!
'개발 > sqld' 카테고리의 다른 글
| [SQL/2과목] Top-N 쿼리 (0) | 2025.08.22 |
|---|---|
| [SQL/2과목] 함수(2) - 다중행 함수(그룹함수, 윈도우함수) (0) | 2025.08.22 |
| [SQL/2과목] 조인이란? (5) | 2025.08.21 |
| [SQL/2과목] 함수(1) - 단일행함수 (0) | 2025.08.20 |
| [SQL/2과목] SELECT문과 구구절절... (4) | 2025.08.17 |