이번 포스팅은 실무 SQL에서 정말 많이 사용하는 서브쿼리(Sub Query)에 대해 소개한다.
※ 서브쿼리란?
앞선 포스팅에서 가장 기본적인 SQL 문법은 [SELECT, FROM, WHERE] 라고 했었다.
서브쿼리란 위치에 따라 SELECT절, FROM절, WHERE절로 나뉘는데,
- SELECT절에 [SELECT, FROM, WHERE]을 넣거나
- FROM절에 [SELECT, FROM, WHERE]을 넣거나
- WHERE절에 [SELECT, FROM, WHERE]을 넣는 구문을 의미한다.
가장 일반적인 것은 WHERE절이며, 실무에선 FROM절과 WHERE절을 가장 많이 사용한다.
예제와 함께 어떻게 서브쿼리를 쓰는지 알아보자!
✔Table of Contents
1. SELECT절 서브쿼리
SELECT절에 사용되는 서브쿼리는 하나의 열처럼 사용된다.
| Q. [MEMBER], [ORDER] 테이블 간 공통값만 매칭하되, [ORDER]는 전부 & [MEMBER]는 gender 열만 나오게 하라.
위 질문에 대해서 저번 포스팅에서 배운 JOIN을 활용하면 다음과 같이 구할 수 있다.
SELECT A.*, B.gender
FROM [ORDER] A
LEFT JOIN [MEMBER] B
ON A.mem_no = B.mem_no
이렇게 LEFT JOIN을 활용한 것을 SELECT절 서브쿼리로 바꿔서 풀면 이렇게 할 수 있다.
SELECT *, (SELECT gender
FROM [MEMBER] B
WHERE B.mem_no = A.mem_no) AS gender
FROM [ORDER] A
즉, [ORDER] 테이블은 전체를(A.*), 그리고 [MEMBER] 테이블의 'gender' 컬럼만 똑 떼어서 가져오는 것이다.
후자를 하는 방법이 SELECT절 서브쿼리이며, SELECT절 서브쿼리가 하나의 'gender' 컬럼처럼 사용되고 있다.
SELECT절 서브쿼리는 데이터의 양이 많을수록 실행속도가 느려지기 때문에 거의 사용되지 않는 명령어이다.
2. FROM절 서브쿼리
FROM절에 사용되는 서브쿼리는 하나의 테이블처럼 사용된다.
테이블처럼 사용되므로, 열 이름과 테이블명을 꼭 명시해줘야 한다!! (FROM절 내 서브쿼리는 괄호를 치고, AS 명시)
| Q. [ORDER] 테이블에서 회원번호(mem_no)별 주문금액(sales_amt) 합계를 집계하라.
위 질문에 대해서 저번 포스팅에서 배운 GROUP BY를 활용하면 다음과 같다.
SELECT mem_no, SUM(sales_amt) AS tot_amt
FROM [ORDER]
GROUP BY mem_no
이렇게 쓴 쿼리를 FROM절로 바꾼다면 이렇게 하나의 테이블처럼 만들면 된다.
SELECT *
FROM (SELECT mem_no, SUM(sales_amt) AS tot_amt
FROM [ORDER]
GROUP BY mem_no) A
위의 예시는 다소 극단적(?)이긴 하다. 처음에 썼던 쿼리를 그냥 FROM절 안에 넣고, SELECT문으로는 전체를 호출했기 때문. 실제로는 이렇게 쿼리를 짜는 경우가 거의 없을 것이다.
실전에서는 여러 가지 테이블을 조인시켜 가공하고, 1차 가공한 결과물을 또다시 2차 가공하고.. 하는 경우가 많다.
1차 가공한 결과를 테이블 형태로 다시 저장하면 좋겠지만 이게 불가능한 경우엔 1차 가공물을 FROM절 서브쿼리에 넣어 하나의 테이블로 이용하는 경우가 많다.
그래서 또다른 예제를 살펴보자.
| Q. 위에서 만든 FROM절 서브쿼리 A 를 기준으로, [MEMBER] 테이블을 LEFT JOIN하여라.
SELECT *
FROM (SELECT mem_no, SUM(sales_amt) AS tot_amt
FROM [ORDER]
GROUP BY mem_no) A
LEFT JOIN [MEMBER] B
ON A.mem_no = B.mem_no
실제론 위 쿼리와 같이 사용되는 경우가 많다. (정말 편리한 FROM절 서브쿼리!)
3. WHERE절 서브쿼리
WHERE절 서브쿼리는 일반 서브쿼리이다. 가장 대표적인 형태이기 때문!
가장 대표적인 예제를 풀어보자.
| Q. [MEMBER] 테이블의 mem_no = '1000005'인 주문내역을 [ORDER] 테이블에서 조회하여라.
SELECT *
FROM [ORDER]
WHERE mem_no IN (SELECT mem_no FROM [MEMBER] WHERE mem_no = '1000005')
이렇게 [MEMBER] 테이블의 mem_no를 조회할 때 WHERE절은 유용하게 쓰인다.
위의 예시는 너무 간단하니 한번 더 해보자!
| Q. [MEMBER] 테이블의 gender = 'man'인 주문내역을 [ORDER] 테이블에서 조회하여라.
SELECT *
FROM [ORDER]
WHERE mem_no IN (SELECT mem_no FROM [MEMBER] WHERE gender = 'man')
이는 [MEMBER] 와 [ORDER] 테이블의 공통열(key)이 mem_no이기 때문에, gender='man'인 mem_no를 WHERE절로부터 찾아내 조회할 수 있었다.
4. 문제로 풀어보기
배운 내용을 문제로 풀어보자. 쿼리를 혼자서 작성해보고 이게 맞는지 확인해보자. ('더보기'를 클릭하면 정답 쿼리를 확인할 수 있다)
| Q. [ORDER] 테이블의 [mem_no] 컬럼별 [sales_amt] 컬럼의 합계를 구하여라. (단, SUM(sales_amt) 열 이름은 tot_amt로 한다.)
SELECT mem_no, sum(sales_amt) tot_amt
FROM [ORDER]
GROUP BY mem_no
결과물은 이렇다.
| Q. 1번 문제에서 짠 쿼리를 서브쿼리로 하여, [MEMBER] 테이블을 LEFT JOIN 하여라.
1번 문제의 쿼리를 FROM절 서브쿼리로 만들면 하나의 테이블처럼 사용할 수 있다.
SELECT *
FROM (SELECT mem_no, sum(sales_amt) tot_amt
FROM [ORDER]
GROUP BY mem_no ) A
LEFT JOIN [MEMBER] B
ON A.mem_no = B.mem_no
결과물은 이렇게!
| Q. 2번 문제에서 짠 쿼리를 바탕으로, [gender]와 [addr] 컬럼별 [tot_amt] 합계를 구하여라. (단, SUM(tot_amt)의 열 이름은 '합계'로 하고, gender와 addr 컬럼은 [MEMBER] 테이블에만 있다.)
위에서 만든 쿼리를 그대로 가져오되, gender와 addr 컬럼으로 GROUP BY를 시키는 것을 추가하자.
SELECT B.gender, B.addr, SUM(tot_amt) AS 합계
FROM (SELECT mem_no, sum(sales_amt) tot_amt
FROM [ORDER]
GROUP BY mem_no ) A
LEFT JOIN [MEMBER] B
ON A.mem_no = B.mem_no
GROUP BY B.gender, B.addr
결과물은 이렇게!
'Skillset > SQL' 카테고리의 다른 글
SQL 자주 사용하는 집계함수 예제로 알아보기 (0) | 2022.05.31 |
---|---|
자주 쓰이는 SQL 연산자 & 함수 정리 (0) | 2022.05.29 |
SQL JOIN 예제 - INNER, LEFT, RIGHT, FULL, CROSS, SELF JOIN (0) | 2022.05.27 |
SQL SELECT 예제 - FROM, WHERE, GROUP BY, HAVING, ORDER BY (0) | 2022.05.26 |
SQL 데이터 추출 / 삽입 / 수정 / 삭제하기 (SQL select, insert, update, delete) (0) | 2022.05.25 |