[SQL] DML: 부속질의(Subquery)
1. 부속질의(Sub-Query)
“가장 비싼 도서의 이름은 무엇인가?”라는 질문의 답을 구한다고 가정하자. 만약 질문이 “가장 비싼 도서의 가격은 무엇인가?” 이었다면 다음과 같은 질의를 작성하면 되며, 35000원이라는 답을 구할 수 있다.
1
2
SELECT MAX(price)
FROM Book;
가장 비싼 도서의 가격을 이용해 아래와 같은 질의를 작성할 수 있다.
1
2
3
SELECT bookname
FROM Book
WHERE price = 35000;
이 두 쿼리를 하나로 합치는 것이 바로 부속질의(subquery)이다.
질의 3-28
가장 비싼 도서의 이름을 나타내시오.
정답
1
2
3
SELECT bookname
FROM Book
WHERE price = (SELECT MAX(price) FROM Book); -- 부속질의(subquery)
질의 결과
bookname |
---|
골프 바이블 |
이처럼 괄호로 또 다른 SELECT 문을 넣는 것을 부속질의라고 하며, 질의가 중첩되어 있다는 의미에서 중첩질의(nested query)라고도 한다.
1.1. 부속질의의 수행 순서
부속질의의 실행 순서는 위와 같다.
WHERE
절의 부속질의를 먼저 처리한다.- 전체질의를 처리한다.
1.2. 부속질의의 반환값
부속질의는 SQL문이므로 결과는 테이블이다. 결과 테이블은 다음 네 가지중 하나가 된다.
- 단일행 - 단일열 ($1 \times 1$)
질의 3-28
처럼 결과를 바로 단일값으로 사용 가능하다.
- 다중행 - 단일열 ($n \times 1$)
- 원소가 여러 개인 집합(배열)과 같으며,
IN
키워드의 대상이 될 수 있다.
- 원소가 여러 개인 집합(배열)과 같으며,
- 단일행 - 다중열 ($1 \times m$)
- 다중행 - 다중열 ($n \times m$)
다음은 다중행 - 단일열 결과를 반환하는 부속질의를 활용하는 질의이다.
질의 3-29
도서를 구매한 적이 있는 고객의 이름을 검색하시오.
정답
1
2
3
SELECT name
FROM Customer
WHERE custid IN (SELECT DISTINCT custid FROM Orders);
- 위 SQL의 부속질의가 실행되면 아래의 SQL과 같아지고, 따라서 주문이 있는 고객의 이름을 보일 수 있다.
1
2
3
SELECT name
FROM Customer
WHERE custid IN (1, 2, 3, 4);
질의 결과
name |
---|
박지성 |
김연아 |
김연경 |
추신수 |
2. 3개 이상 중첩된 부속질의
부속질의는 당연히 3개 이상 중첩해서도 사용할 수 있다.
질의 3-30
대한미디어에서 출판한 도서를 구매한 고객의 이름을 보이시오.
정답
1
2
3
4
5
6
7
8
9
SELECT name -- (3)
FROM Customer
WHERE custid IN/* '='는 사용할 수 없다! */(
SELECT custid -- (2)
FROM Orders
WHERE bookid IN/* '=' 사용 불가능 */(
SELECT bookid -- (1)
FROM Book
WHERE publisher LIKE '대한미디어'));
부속질의 결과가 다중행 단일열 테이블로 반활될 가능성이 있을 경우,
=
의 사용은 금지된다!IN
을 사용하자.
질의 결과
name |
---|
박지성 |
위와 같은 부속질의문은 밑에서부터 읽어나가야 한다. 이유는 (1)
, (2)
, (3)
의 순서로 실행되기 때문이다.
다음은 3단계 부속질의의 실행 순서와 데이터의 예이다.
3. 상관 부속질의
만약 안쪽 질의문(subquery)에서 바깥쪽 질의문(main query)의 테이블이나 속성을 참조하는 경우, DBMS는 이를 감지하여 일반 부속질의와는 다른 동작을 하게 되는데 이를 상관 부속질의(correlated subquery) 또는 상호연관 부속질의라고 한다. 일반 부속질의는 말 그대로 subquery는 main query와 관계 없이 독립적으로 실행되는 반면, 상관 부속질의는 main query와 종속되어 실행된다는 특징이 있다.
상관 부속질의는 상위 부속질의의 튜플을 이용해 하위 부속질의를 계산하는 유형이다. 즉 상관 부속질의는 질의문을 계산할 바깥쪽 질의문의 튜플을 가져와 그 튜플을 이용하는 계산을 수행한다. 과정을 조금 더 자세히 설명하면 다음과 같다.
- GET: 바깥쪽 쿼리(main query)가 한 행을 안쪽 쿼리(sub(correlated) query)에 제공한다.
- EXECUTE: 안쪽 쿼리는 제공받은 행의 특정 열의 값을 이용하여 본인의 쿼리를 실행한다.
- USE: 바깥쪽 쿼리는 안쪽 쿼리의 결과를 토대로 제공한 행을 결과에 포함할지 제외할 지 결정한다.
요약하자면, 상관 부속질의는 메인 쿼리의 결과를 이용해 서브 쿼리가 실행되고, 그 결과로 메인 쿼리가 또 실행되는 서로 연관된 쿼리이다.
질의 3-31
출판사별로 출판사의 평균 도서 가격보다 비싼 도서를 구하시오.
정답
1
2
3
4
5
6
SELECT b1.publisher, b1.bookname
FROM Book b1
WHERE b1.price > (
SELECT AVG(b2.price)
FROM Book b2
WHERE b2.publisher = b1.publisher);
질의 결과
publisher | bookname |
---|---|
대한미디어 | 골프 바이블 |
굿스포츠 | 피겨 교본 |
이상미디어 | 야구의 추억 |
4. 부속질의와 Join의 차이점
- 공통점
- 부속질의, Join 모두 여러 테이블을 하나의 SQL문에서 다룬다.
- 차이점
- 부속질의
SELECT
문에 나오는 결과 속성을FROM
절의 테이블에서만 얻을 수 있음- Join 문과는 다른 부속질의만의 편리함과 간결함이 있음
- Join
SELECT
문에 나오는 결과 속성을 조인한 모든 테이블에서 얻을 수 있음- 부속질의에서 가능한 모든 것을 할 수 있음
- 부속질의
만약 한 개의 테이블에서만 결과를 얻는 여러 테이블에 대한 질의를 하는 경우, 부속질의로 작성하는 것이 훨씬 편하다.