서브쿼리는 SQL에서 쿼리 안에 다른 쿼리를 사용하는 것을 말한다. 일반적으로 소괄호 안에 작성되고 메인 쿼리 또는 외부 쿼리에서 그 결과를 사용한다.
SELECT, FROM, WHERE, HAVING, JOIN절 등에 포함될 수 있는 중첩된 쿼리이다. 이 쿼리는 메인 쿼리에 값을 제공하거나 조건을 설정하는데 사용된다.
테이블 스키마는 아래와 같다.
CREATE TABLE employee
(
employee_id INT PRIMARY KEY AUTO_INCREMENT,
name VARCHAR(100) NOT NULL,
salary DECIMAL(15, 2) NOT NULL,
department_id INT,
FOREIGN KEY (department_id) REFERENCES department (department_id)
);
CREATE TABLE department
(
department_id INT PRIMARY KEY AUTO_INCREMENT,
name VARCHAR(100) NOT NULL,
location VARCHAR(100)
);
하나의 값을 반환한다.
SELECT name
FROM employee
WHERE department_id = (SELECT department_id
FROM department
WHERE name = 'HR');
FROM 절에 들어가 테이블처럼 사용된다.
SELECT avg_salary.department_id, avg_salary.avg
FROM (SELECT department_id, AVG(salary) AS avg
FROM employee
GROUP BY department_id) AS avg_salary;
여러 행을 반환하며, IN, ANY, ALL과 함께 사용된다.
SELECT name
FROM employee
WHERE department_id IN (SELECT department_id
FROM department
WHERE location = 'Seoul');
서브쿼리가 메인 쿼리의 값을 참조한다. 메인 쿼리의 각 행마다 서브쿼리가 실행된다.
SELECT name
FROM employee e
WHERE salary > (SELECT AVG(salary)
FROM employee
WHERE department_id = e.department_id);
FROM절에 서브쿼리를 제한하거나, 특정 서브쿼리 형태를 지원하지 않는 경우가 있다.서브쿼리는 가끔 JOIN, Common Table Expressions, 윈도우 함수 등으로 대체 가능하며, 이 경우 성능과 가독성이 개선될 수 있다.
-- 원본 SQL
SELECT e.name, a.avg
FROM employee e
JOIN (SELECT department_id, AVG(salary) AS avg
FROM employee
GROUP BY department_id) a ON e.department_id = a.department_id;
-- 서브쿼리가 대체된 SQL
WITH avg_salary AS (SELECT department_id, AVG(salary) AS avg
FROM employee
GROUP BY department_id)
SELECT e.name, a.avg
FROM employee e
JOIN avg_salary a ON e.department_id = a.department_id;
FROM절 안에 서브쿼리를 직접 넣어서 avg_salary테이블처럼 사용한 형태이다.