쿼리 내부에서 또 다른 SELECT문을 사용하는 것
즉, 하위 SELECT문이 다른 SQL 명령어의 일부로 사용되는 구조
-- 기본 형태
SELECT 컬럼
FROM 테이블
WHERE 컬럼 = (SELECT ... FROM ...)
-- 역대 최고 연봉을 받은 선수의 정보 조회
SELECT *
FROM players
WHERE playerID = (
SELECT TOP 1 playerID
FROM salaries
ORDER BY salary DESC
);
SELECT TOP 1은 가장 높은 연봉을 가진 선수 1명의playerID만 반환
→ 결과적으로WHERE playerID = '...'처럼 작동
-- 상위 20명의 연봉을 받은 선수 정보 조회
SELECT *
FROM players
WHERE playerID IN (
SELECT TOP 20 playerID
FROM salaries
ORDER BY salary DESC
);
🎯
IN은 서브쿼리가 여러 값을 반환할 때 사용
✅ 중복된 playerID는 자동 제거됨
→ 실질적으로 20명이 아닌 중복 제거 후 적은 수가 나올 수 있음
-- 각 테이블의 총 행 수를 한 번에 조회
SELECT
(SELECT COUNT(*) FROM players) AS playerCount,
(SELECT COUNT(*) FROM batting) AS battingCount;
💡 서브쿼리의 결과를 컬럼처럼 활용 가능
→ 쿼리 한 번으로 다양한 요약 정보 조회 가능
VALUES 안에서 사용-- 최고 연봉으로 새로운 행 삽입
INSERT INTO salaries
VALUES (2020, 'KOR', 'NL', 'rookiss5', (SELECT MAX(salary) FROM salaries));
INSERT INTO ... SELECT 문 전체를 서브쿼리로 사용-- INSERT INTO SELECT → 서브쿼리로 행 전체 삽입
INSERT INTO salaries
SELECT 2020, 'KOR', 'NL', 'rookiss6', (SELECT MAX(salary) FROM salaries);
| 방식 | 특징 |
|---|---|
INSERT INTO ... VALUES | 하나의 행 삽입 |
INSERT INTO ... SELECT | 여러 행을 한꺼번에 삽입 가능 |
대량 데이터 마이그레이션 시
SELECT기반 방식이 유용
-- 포스트 시즌에 참가한 선수 조회 (IN 방식)
SELECT *
FROM players
WHERE playerID IN (
SELECT playerID
FROM battingpost
);
-- 포스트 시즌에 참가한 선수 조회 (EXISTS 방식)
SELECT *
FROM players
WHERE EXISTS (
SELECT 1
FROM battingpost
WHERE battingpost.playerID = players.playerID
);
🎯
EXISTS는 조건을 만족하는 행이 존재하는가?만 판단
성능상IN보다 빠를 수 있음 (특히 하위 쿼리 결과가 많을 때)
→ 일반적으로 상관 서브쿼리에 활용
| 상황 | 주의할 점 |
|---|---|
= 사용 시 | 서브쿼리 결과가 반드시 하나여야 함 |
| 다중행 결과일 때 | 반드시 IN, ANY, ALL 등의 연산자 사용 필요 |
| SELECT 서브쿼리 | 열 이름에 AS 별칭을 붙여주면 가독성 ↑ |
| INSERT 서브쿼리 | SELECT 방식이면 여러 행 삽입도 가능 |