하나의 SQL 문 안에 포함되어 있는 또 다른 SQL 문을 말한다.
메인쿼리가 서브쿼리를 포함하는 종속적인 관계이다.
• 서브쿼리는 메인쿼리의 칼럼 사용 가능
• 메인쿼리는 서브쿼리의 칼럼 사용 불가
• Subquery 는 괄호로 묶어서 사용
• 단일 행 혹은 복수 행 비교 연산자와 함께 사용 가능
• subquery 에서는 order by 를 사용X
• 스칼라 서브쿼리 (Scalar Subquery) - SELECT 절에 사용
• 인라인 뷰 (Inline View) - FROM 절에 사용
• 중첩 서브쿼리 (Nested Subquery) - WHERE 절에 사용
SELECT column1, (SELECT column2 FROM table2 WHERE condition) FROM table1 WHERE condition;
1) 서울은평경찰서의 강도 검거 건수
SELECT case_number FROM crime_status WHERE police_station LIKE '은평' AND crime_type LIKE '강도' AND status_type LIKE '검거';
2) 서울시 경찰서 전체의 평균 강도 검거 건수
SELECT avg(case_number) FROM crime_status WHERE crime_type LIKE '강도' AND status_type LIKE '검거'
3) 전체
SELECT case_number, (SELECT avg(case_number) FROM crime_status WHERE crime_type LIKE '강도' AND status_type LIKE '검거') avg FROM crime_status WHERE police_station LIKE '은평' AND crime_type LIKE '강도' AND status_type LIKE '검거';
FROM 절에 사용하는 서브쿼리. 메인쿼리에서는 인라인 뷰에서 조회한 Column 만 사용가능하다.
쿼리가 실행된 결과 set을 하나의 table로 인식한다 (이걸 view table 이라고 한다)
SELECT a.column, b.column FROM table a, (SELECT column1, column2 FROM table2) b WHERE condition;
1) 경찰서 별로 가장 많이 발생한 범죄 건수
이 결과가 테이블이 되어서 (alis m)
SELECT police_station, max(case_number) count FROM crime_status WHERE status_type LIKE '발생' GROUP BY police_station;
2) 전체
SELECT c.police_station, c.crime_type, c.case_number FROM crime_status c, (SELECT police_station, max(case_number) count FROM crime_status WHERE status_type LIKE '발생' GROUP BY police_station) m WHERE c.police_station = m.police_station AND c.case_number = m.count;
WHERE 절에서 사용하는 서브쿼리.
• Single Row - 하나의 행을 검색(반환)하는 서브쿼리
• Multiple Row - 하나 이상의 행을 검색(반환)하는 서브쿼리
• Multiple Column - 하나 이상의 열을 검색(반환)하는 서브쿼리
서브쿼리가 비교연산자( =, >, >=, <, <=, <>, !=)와 사용되는 경우,
서브쿼리의 검색 결과는 한 개의 결과값을 가져야 한다. (두개 이상인 경우 에러)
# = 등호가 있다 (비교연산자 예시) SELECT column_names FROM table_name WHERE column_name = (SELECT column_name FROM table_name WHERE condition) ORDER BY column_name;
SELECT name FROM celeb WHERE name = SELECT host FROM snl_show;
SELECT name FROM celeb WHERE name = (SELECT host FROM snl_show);
SELECT name FROM celeb WHERE name = (SELECT host FROM snl_show WHERE id =1);
# IN과 함께 사용되는 경우 SELECT column_names FROM table_name WHERE column_name IN (SELECT column_name FROM table_name WHERE condition) ORDER BY column_names;
1) 영화배우를 조회
SELECT name
FROM celeb
WHERE job_title LIKE '%영화배우%'
2) snl 에 출연한 영화배우
SELECT host
FROM snl_show;
3) 전체
# IN과 함께 사용되는 경우 SELECT host FROM snl_show WHERE host IN (SELECT name FROM celeb WHERE job_title LIKE '%영화배우%');
# EXISTS 함께 사용되는 경우 SELECT column_names FROM table_name WHERE column_name EXISTS (SELECT column_name FROM table_name WHERE condition) ORDER BY column_names;
1) 건수가 2000건 보다 큰 경찰서
SELECT police_station, reference FROM crime_status WHERE case_number > 2000;
2) 전체
# EXISTS 함께 사용되는 경우 SELECT name FROM police_station p WHERE EXISTS (SELECT police_station FROM crime_status c WHERE p.name = c.reference AND case_number > 2000);
서브쿼리 결과 중에 최소한 하나라도 만족하면 True 리턴(비교연산자 사용)
# ANY 함께 사용되는 경우 SELECT column_names FROM table_name WHERE column_name = ANY (SELECT column_name FROM table_name WHERE condition) ORDER BY column_names;
# ANY 함께 사용되는 경우 SELECT name FROM celeb WHERE name = ANY (SELECT host FROM snl_show);
서브쿼리 결과를 모두 만족하면 (비교 연산자 사용)
ANY와 달리 ALL은 모두 만족해야하므로 WHERE 조건을 붙임
# ALL 함께 사용되는 경우 SELECT column_names FROM table_name WHERE column_name = ALL (SELECT column_name FROM table_name WHERE condition) ORDER BY column_names;
# ALL 함께 사용되는 경우 SELECT name FROM celeb WHERE name = ALL (SELECT host FROM snl_show WHERE id = 1);
Multi Column Subquery(연관서브쿼리) :컬럼 여러개를 반환하는 쿼리
서브쿼리 내에 메인쿼리 컬럼이 같이 사용되는 경우.
SELECT column_names FROM tablename a WHERE (a.column1, a.column2, ...) IN (SELECT b.column1, b.column2, ... FROM tablename b WHERE a.cloumn_name = b.column_name) ORDER BY column_names;
SELECT name, sex, agency FROM celeb LIMIT 2;
SELECT sex, agency FROM celeb WHERE name = '강동원';
SELECT name, sex, agency FROM celeb WHERE (sex, agency) IN (SELECT sex, agency FROM celeb WHERE name = '강동원');
SELECT * FROM oil_price LIMIT 1;
SELECT avg(가격) FROM oil_price WHERE 셀프='Y';
SELECT MAX(가격) FROM oil_price WHERE 상표='SK에너지';
SELECT MAX(가격), (SELECT avg(가격) FROM oil_price WHERE 셀프='Y') FROM oil_price WHERE 상표='SK에너지';
SELECT 상표, MAX(가격) FROM oil_price GROUP BY 상표;
SELECT o.상호, o.상표, s.max_price FROM oil_price o, (SELECT 상표, MAX(가격) max_price FROM oil_price GROUP BY 상표) s WHERE o.상표 = s.상표 AND o.가격 = s.max_price;
SELECT avg(가격) FROM oil_price;
SELECT 상호, 가격 FROM oil_price WHERE 가격 > (SELECT avg(가격) FROM oil_price);
SELECT * FROM refueling LIMIT 1;
SELECT 이름, 주유소, 주유일 FROM refueling WHERE 주유소 IN (SELECT 상호 FROM oil_price WHERE 가격 > (SELECT AVG(가격) FROM oil_price));
SELECT 이름, 주유소, 금액 FROM refueling WHERE 금액 >= 100000;
SELECT r.이름, o.상호, o.상표, r.금액, o.가격 FROM refueling o, (SELECT 이름, 주유소, 금액 FROM refueling WHERE 금액 >= 100000) r WHERE o.상호 = r.주유소;
위 글은 제로베이스 데이터 취업 스쿨의 강의자료를 참고하여 작성되었습니다.