👉 메인쿼리 안에서 SELECT, FROM, WHERE, HAVING, 또는 IN 절과 함께 사용
✅ 서브쿼리의 예
SELECT * FROM t1 WHERE column1 = (SELECT column1 FROM t2);
✅ 예제 테이블들
-- customers 테이블 생성
DROP TABLE customers;
CREATE TABLE customers(
id INT AUTO_INCREMENT PRIMARY KEY,
name VARCHAR(50),
email VARCHAR(50),
phone VARCHAR(20)
);
-- customers 테이블에 데이터 추가
INSERT INTO customers (name, email, phone)
VALUES
('Alice', 'alice@example.com', '123-4567'),
('Bob', 'bob@example.com', '234-5678'),
('Charlie', 'charlie@example.com', '345-6789'),
('David', 'david@example.com', '456-7890');
-- orders 테이블 생성
DROP TABLE IF EXISTS orders;
CREATE TABLE orders (
id INT AUTO_INCREMENT PRIMARY KEY,
customer_id INT,
order_date DATE
);
-- orders 테이블에 데이터 추가
INSERT INTO orders (customer_id, order_date) VALUES
(1, '2022-03-01'),
(1, '2022-03-03'),
(2, '2022-03-02'),
(3, '2022-03-01'),
(3, '2022-03-04'),
(3, '2022-03-05'),
(4, '2022-03-01'),
(4, '2022-03-03'),
(4, '2022-03-04');
01. 스칼라 서브쿼리(Scalar Subquery)
✅ 스칼라 서브쿼리
👉 SELECT 문 내부에 사용되며, 서브쿼리 결과는 스칼라임
👉 서브쿼리의 결과가 단일 값(스칼라)인 경우에 사용
👉 특정 테이블에서 가장 높은값, 낮은 값, 또는 평균값을 가져오는 등의 작업을 할 때 사용
SELECT column1, (SELECT MAX(column2) FROM table2) AS max_value FROM table1;
➡️ customers 테이블에서 가장 많은 주문을 한 고객의 이름과 주문수
SELECT name,
(SELECT COUNT(*)
FROM orders
WHERE orders.customer_id = customers.id) AS order_count
FROM customers
ORDER BY order_count DESC
LIMIT 1;
02. 인라인 뷰 서브쿼리(Inline View Subquery)
✅ 인라인뷰 서브쿼리
👉 테이블 형태의 결과를 반환
👉 From 절 내부에 사용되며, 서브쿼리의 결과는 하나 이상의 컬럼을 반환
SELECT column1, column2
FROM (SELECT column1, column2 FROM table1) AS subquery
WHERE column1 > 10;
➡️ orders 테이블에서 가장 많은 주문을 한 고객의 이름과 주문 수를 찾기
SELECT customers.name, order_counts.order_count
FROM customers
JOIN (
SELECT customer_id, COUNT(*) AS order_count
FROM orders
GROUP BY customer_id
ORDER BY order_count DESC
LIMIT 1
) AS order_counts
ON customers.id = order_counts.customer_id;
03. 상관 서브쿼리(Correlated Subquery)
✅ 상관 서브쿼리
👉 WHERE 절 내부에 사용
👉 서브쿼리의 결과는 외부 쿼리의 컬럼을 기반으로 계산
SELECT column1
FROM table1
WHERE column2 > (SELECT AVG(column2) FROM table1 WHERE table1.column1 = column1);
➡️ orders 테이블에서 주문한 고객의 이름, 해당 고객의 총 주문 건수를 계산해 출력하는 상관 서브쿼리
SELECT c.name, (
SELECT COUNT(*)
FROM orders o
WHERE o.customer_id = c.id
) AS total_orders
FROM customers c;
04. EXISTS 서브쿼리
✅ EXISTS 서브쿼리
👉 WHERE OR HAVING 절 내부에 사용
👉 서브쿼리의 결과가 존재하는지 여부에 따라 TRUE/FALSE 값을 반환
SELECT column1
FROM table1
WHERE EXISTS (SELECT column2 FROM table2 WHERE table1.column1 = table2.column2);
➡️ 3월 3일에 주문을 한 적이 있는 고객의 이름과 이메일 주소
SELECT name, email
FROM customers c
WHERE EXISTS (
SELECT *
FROM orders o
WHERE o.customer_id = c.id
AND o.order_date ='2022-03-03'
);
➡️ 3월 3일에주문을 한 적이 없는 고객의 이름과 이메일 주소
SELECT name, email
FROM customers c
WHERE NOT EXISTS (
SELECT *
FROM orders o
WHERE o.customer_id = c.id
AND o.order_date ='2022-03-03'
);
05. 비교 연산자를 사용한 서브쿼리
✅ 비교 연산자를 사용한 서브쿼리
👉 WHERE 절 내부에 사용
👉 서브쿼리의 결과가 비교 연산자(> , < , = 등)와 함께 사용
SELECT column1
FROM table1
WHERE column2 > ANY (SELECT column2 FROM table2 WHERE column3 = 'value');
➡️ ANY 연산자를 사용한 서브쿼리
: 서브쿼리의 결과 중 하나라도 조건을 만족하는 경우 조건식이 참이 됨.
: 3월 3일과 3월 5일 사이에 주문한 고객의 정보
SELECT *
FROM customers
WHERE id = ANY (
SELECT customer_id
FROM orders
WHERE order_date BETWEEN '2022-03-03' AND '2022-03-05'
);
➡️ ALL 연산자를 사용한 서브쿼리
: 서브쿼리의 모든 결과가 조건을 만족해야 전체 조건식이 참이 됨
: 주문을 2건 이상하지 않은 고객 출력
SELECT *
FROM customers
WHERE id <> ALL (
SELECT customer_id
FROM orders
GROUP BY customer_id
HAVING count(*) >=2
);