SQL SubQuery (서브쿼리) 종류 및 정리

SubQuery는 SQL을 작성하다 보면 빠질 수 없는 문법입니다.

서브쿼리에 종류와 특징을 파악하고 적절하게 사용할 줄 안다면 큰 도움이 될 것입니다.

 

 

SubQuery의 종류

1. 일반 서브쿼리 : 하나의 변수처럼 사용합니다. 쿼리 결과에 따라 다음과 같이 구분됩니다.

  - 단일행 서브쿼리 (SingleRow Subquery) : 쿼리 결과가 단일행만을 리턴하는 서브쿼리입니다.

  - 다중행 서브쿼리 (MultieRow Subquery) : 쿼리 결과가 다중행을 리턴하는 서브쿼리입니다.

  - 다중칼럼 서브쿼리 (MultieColumn Subquery) : 쿼리 결과가 다중칼럼을 리턴하는 서브쿼리입니다.

 

2. 인라인 뷰 (Inline View) : 뷰 형태로써 테이블을 리턴하는 서브쿼리입니다. (테이블 대체)

FROM 내 쿼리 또는 JOIN 할 테이블을 리턴할 때 사용하는 서브쿼리입니다.

 

3. 스칼라 서브쿼리 (Scalar Subquery) : 하나의 칼럼처럼 사용되는 서브쿼리입니다.

 

* 상호 연관 서브쿼리 (Correlative Subquery) : 메인 쿼리의 값을 사용하는 서브쿼리입니다.

즉 메인 쿼리의 결과로 서브쿼리가 실행되고 그 결과로 메인쿼리가 또 실행되는 서로 연관된 쿼리를 의미합니다.

넘버링을 하지 않은 건 중복되는 분류이기 때문입니다. (스칼라 서브쿼리이면서 상호 연관 서브쿼리 일 수 있습니다.)

 

예제에 쓰일 테이블로 T_GRADE와 T_PERSON이 있습니다.

T_GRADE

PERSON_NO GRADE
1 A
2 B
3 A

T_PERSON

PERSON_NO NAME AGE
1 Aiden 20
2 Matthew 20
3 John 19

 

일반 서브쿼리

일반적인 서브쿼리로써 변수처럼 사용합니다.

이름이 Aiden 인 사람의 GRADE를 얻으려면 어떻게 해야 할까요?

# 서브쿼리가 없을때
DECLARE @PERSON_NO INT

SELECT @PERSON_NO = A.PERSON_NO
  FROM T_PERSON A
 WHERE A.NAME = 'Aiden'
 
SELECT A.GRADE
  FROM T_GRADE A
 WHERE A.PERSON_NO = @PERSON_NO

# 서브쿼리 사용하면
SELECT A.GRADE
  FROM T_GRADE A
 WHERE A.PERSON_NO = (SELECT B.PERSON_NO
                        FROM T_PERSON B
                       WHERE B.NAME = 'Aiden')

이런 식으로 실제 'Aiden'의 PERSON_NO인 1 변수에 담아 조회할 때 사용하는 대신에

서브 쿼리로 이름이 'Aiden'인 사람의 PERSON_NO를 리턴하여서

T_GRADE의 WHERE절에 PERSON_NO의 조건으로 겁니다.

 

이때 서브 쿼리의 아웃풋의 종류에 따라 

단일행 서브쿼리, 다중행서브 쿼리, 다중칼럼 서브쿼리로 나뉩니다.

위의 예제처럼 하나의 행만 리턴하는 경우를 단일행 서브쿼리(SingleRow Subquery)라고 합니다.

* 단일행을 리턴하기 때문에 단일행 비교 연산자 (=, >, <, <>) 만 사용해야 합니다.

 

다음은 GRADE가 A인 모든 사람을 출력하고 싶을 때

SELECT A.NAME
  FROM T_PERSON A
 WHERE A.PERSON_NO IN (SELECT B.PERSON_NO
                         FROM T_GRADE B
                        WHERE GRADE = 'A')

현재 GRADE 테이블에는 GRADE 가 'A'인 행이 2개이기 때문에 2줄의 행이 리턴됩니다.

위 예제처럼 여러 행을 리턴하는 경우를 다중행 서브쿼리(MultieRow Subquery)라고 합니다.

* 다중행을 리턴하기 때문에 다중행 비교 연산자 (IN, ANY, SOME, EXISTS 등)를 사용해야 합니다.

 

다음은 다중칼럼 서브쿼리 예제입니다.

SELECT *
  FROM T_PERSON A
 WHERE (A.NAME, A.AGE) IN (SELECT B.NAME, B.AGE
                             FROM T_PERSON B
                            WHERE B.PERSON_NO < 3)

위 예제처럼 두 개 이상의 칼럼을 리턴하는 경우를 다중칼럼 서브쿼리(MultieColumn Subquery)라고 합니다.

 

인라인 뷰 (Inline View)

인라인 뷰는 서브쿼리가 하나의 테이블처럼 사용되는 경우입니다.

굉장히 많이 쓰이는 문법이며 유용합니다.

#Subquery 없이 일반적인 테이블 Join
SELECT
  FROM T_PERSON A
        INNER JOIN T_GRADE B ON (B.PERSON_NO = A.PERSON_NO)
 WHERE B.GRADE = 'A'

#Inline View Subquery
SELECT *
  FROM T_PERSON A
        INNER JOIN (
            SELECT PERSON_NO
              FROM T_GRADE A
             WHERE A.GRADE = 'A'
        ) B ON (B.PERSON_NO = A.PERSON_NO)

 

 

위처럼 실제 테이블 대신에 서브쿼리의 결과를 테이블처럼 사용하는 경우를 인라인 뷰(Inline View)라고 합니다.

위 예제는 굉장히 단순하게 만들었지만 활용은 정말 무궁무진하고 많이 사용되는 쿼리입니다.

 

스칼라 서브쿼리 (Scalar Subquery)

스칼라 서브쿼리는 SELECT 절에서 서브쿼리를 사용하여 하나의 칼럼처럼 사용되는 쿼리를 의미합니다.

SELECT A.PERSON_NO
     , A.NAME
     , (SELECT G.GRADE
          FROM T_GRADE G
         WHERE G.PERSON_NO = A.PERSON_NO) AS GRADE
  FROM T_PERSON A

 

칼럼의 역할을 하기 때문에 해당 서브쿼리는 반드시 한 개의 ROW만을 리턴해야 합니다.

위처럼 칼럼으로써 사용되는 서브쿼리를 스칼라 서브쿼리(Scalar Subquery)라고 합니다.

※ 스칼라 서브쿼리는 성능이 좋지도 않고 웬만하면 조인으로도 다 표현이 가능하니

꼭 필요 한경 우만 쓰시는 걸 장려합니다.

 

상호연관 서브쿼리 (Correlative Subquery)

상호연관 서브쿼리는 서브쿼리와 메인쿼리가 서로 연관돼있는 경우를 말합니다.

SELECT A.PERSON_NO
     , A.NAME
     , (SELECT G.GRADE
          FROM T_GRADE G
         WHERE G.PERSON_NO = A.PERSON_NO) AS GRADE
  FROM T_PERSON A

스칼라 서브쿼리와 예제가 똑같은데요? 라고 하실 수 있겠습니다.

네 위 예제는 스칼라 서브쿼리이면서 동시에 상호연관 서브쿼리입니다.

위 서브쿼리의 G테이블은 WHERE절에서 메인쿼리의 A테이블과 비교하고 있습니다.

이런 식으로 메인쿼리의 값을 사용하는 서브쿼리를 상호연관 서브쿼리(Correlative Subquery)라고 합니다.

해당 서브쿼리는 메인쿼리의 값이 없으면 실행될 수 없습니다.

그래서 모든 행마다 서브쿼리와 메인쿼리가 정보를 주고받으며 연산합니다.

★★ 데이터양이 많다면 상당히 느려질 수 있습니다. 

※ 스칼라 서브쿼리뿐만 아니라 인라인 뷰, 일반 서브쿼리도 메인쿼리와 값을 비교하면 상호연관 서브쿼리입니다.