포스트

[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. 부속질의의 수행 순서

1.1. 부속질의의 수행 순서 부속질의의 수행 순서

부속질의의 실행 순서는 위와 같다.

  1. WHERE 절의 부속질의를 먼저 처리한다.
  2. 전체질의를 처리한다.

1.2. 부속질의의 반환값

부속질의는 SQL문이므로 결과는 테이블이다. 결과 테이블은 다음 네 가지중 하나가 된다.

  1. 단일행 - 단일열 ($1 \times 1$)
    • 질의 3-28처럼 결과를 바로 단일값으로 사용 가능하다.
  2. 다중행 - 단일열 ($n \times 1$)
    • 원소가 여러 개인 집합(배열)과 같으며, IN 키워드의 대상이 될 수 있다.
  3. 단일행 - 다중열 ($1 \times m$)
  4. 다중행 - 다중열 ($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단계 부속질의의 실행 순서와 데이터의 예이다.

2. 3개 이상 중첩된 부속질의 3단계 부속질의의 실행 순서

2. 3개 이상 중첩된 부속질의 2 3단계 부속질의의 실행 순서와 데이터의 예

3. 상관 부속질의

만약 안쪽 질의문(subquery)에서 바깥쪽 질의문(main query)의 테이블이나 속성을 참조하는 경우, DBMS는 이를 감지하여 일반 부속질의와는 다른 동작을 하게 되는데 이를 상관 부속질의(correlated subquery) 또는 상호연관 부속질의라고 한다. 일반 부속질의는 말 그대로 subquery는 main query와 관계 없이 독립적으로 실행되는 반면, 상관 부속질의는 main query와 종속되어 실행된다는 특징이 있다.

상관 부속질의상위 부속질의의 튜플을 이용해 하위 부속질의를 계산하는 유형이다. 즉 상관 부속질의는 질의문을 계산할 바깥쪽 질의문의 튜플을 가져와 그 튜플을 이용하는 계산을 수행한다. 과정을 조금 더 자세히 설명하면 다음과 같다.

  1. GET: 바깥쪽 쿼리(main query)가 한 행을 안쪽 쿼리(sub(correlated) query)에 제공한다.
  2. EXECUTE: 안쪽 쿼리는 제공받은 행의 특정 열의 값을 이용하여 본인의 쿼리를 실행한다.
  3. 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);


질의 결과

publisherbookname
대한미디어골프 바이블
굿스포츠피겨 교본
이상미디어야구의 추억

3. 상관 부속질의 상관 부속질의의 데이터의 예

4. 부속질의와 Join의 차이점

  • 공통점
    • 부속질의, Join 모두 여러 테이블을 하나의 SQL문에서 다룬다.
  • 차이점
    • 부속질의
      • SELECT 문에 나오는 결과 속성을 FROM 절의 테이블에서만 얻을 수 있음
      • Join 문과는 다른 부속질의만의 편리함과 간결함이 있음
    • Join
      • SELECT 문에 나오는 결과 속성을 조인한 모든 테이블에서 얻을 수 있음
      • 부속질의에서 가능한 모든 것을 할 수 있음

만약 한 개의 테이블에서만 결과를 얻는 여러 테이블에 대한 질의를 하는 경우, 부속질의로 작성하는 것이 훨씬 편하다.

이 포스팅은 작성자의 CC BY-NC 4.0 라이선스를 준수합니다.