우와한 개발자

[SQL] 서브쿼리(Subquery)란? 상관서브쿼리 / 스칼라와 인라인뷰 / 단일행과 다중행 서브쿼리 / 서브쿼리와 메인쿼리 참조

by 우와한개발자

 

1. 서브쿼리란?

  • 서브쿼리란 하나의 SQL문 안에 포함된 또 다른 SQL문
  • 메인 쿼리가 실행되기 전에 서브쿼리가 먼저 실행되고, 그 결과를 메인 쿼리가 사용
  • 메인쿼리 : 서브쿼리를 감싸고 있는 바깥쪽 쿼리 (외부쿼리)

 

2. 참조에 따른 서브쿼리의 종류

1) 연관 서브쿼리 Correlated Subquery

  • 외부 쿼리의 컬럼을 참조하는 서브쿼리
  • 외부쿼리의 각 행마다 서브쿼리가 된다
  • 반복 실행
SELECT 이름, 부서, 급여
FROM 직원 e1
WHERE 급여 > (
    SELECT AVG(급여)
    FROM 직원 e2
    WHERE e2.부서 = e1.부서  -- 외부 참조
);

 

2) 비연관 서브쿼리 Independent Subquery

  • 외부 쿼리와 독립적으로 실행되는 서브쿼리
  • 서브쿼리가 먼저 1번만 실행되고, 그결과를 메인쿼리가 사용
  • 옵티마이저가 1번만 실행하도록 최적화함
SELECT 이름, 급여
FROM 직원
WHERE 급여 > (SELECT AVG(급여) FROM 직원);

 

3. 반환 행 수에 따른 서브쿼리 종류

1) 단일 행 서브쿼리 Single Row Subquery

  • 1개이하의 행만 반환하는 서브쿼리
  • 비교 연산자(=, >, <, >=, <=, !=)와 함께 사용
  • 컬럼의 갯수가 왼쪽항과 같아야함.
    연산자 의미 서브쿼리 컬럼 개수
    = 같다 1개 또는 여러 개(튜플 가능)
    > 크다 ❗ 1개만 가능
    < 작다 ❗ 1개만 가능
    >= 크거나 같다 ❗ 1개만 가능
    <= 작거나 같다 ❗ 1개만 가능
    <> 또는 != 같지 않다 ❗ 1개만 가능
    BETWEEN 범위 ❗ 1개만 가능
    LIKE 패턴 검색 ❗ 1개만 가능
    IS NULL NULL 여부 ❗ 1개만 가능
SELECT 이름
FROM 직원
WHERE 급여 = (SELECT MAX(급여) FROM 직원);

 

2) 다중 행 서브쿼리 Multiple Row Subquery

  • 여러 행을 반환하는 서브쿼리
  • 다중행 비교 연산자(IN, ANY, ALL, EXISTS)와 함께 사용
  • EXISTS를 제외하고 컬럼의 갯수는 왼쪽과 같아야함.연산자 의미 컬럼 개수
    IN 여러 값 중 하나 ⭕ 여러 컬럼 가능
    NOT IN 여러 값 모두와 다름 ⭕ 여러 컬럼 가능
    ANY 하나라도 만족 ❗ 1개만 가능
    ALL 모두 만족 ❗ 1개만 가능
    EXISTS 반환되는 행이 있는지 하나라도 있는지 컬럼 개수 상관 없음
SELECT 이름
FROM 직원
WHERE 부서 IN (SELECT 부서명 FROM 부서 WHERE 지역 = '서울');

SELECT 이름
FROM 직원
WHERE 급여 < ANY (300, 400, 500)

SELECT 이름
FROM 직원
WHERE 급여 > ALL (SELECT 급여 FROM 직원 WHERE 부서 = 'IT');

SELECT 고객명
FROM 고객 c
WHERE EXISTS ( SELECT 1 FROM 주문 o  WHERE o.고객ID = c.고객ID);

 

4. 위치에 따른 서브쿼리 종류

1) 스칼라 서브쿼리 Scalar Subquery : SELECT 절

  • SELECT 절에 오는 서브쿼리
  • 단일행 반환
  • (연관 스칼라 경우) 메인 쿼리의 각 행마다 서브쿼리가 실행.
  • 서브쿼리의 별칭/컬럼을 외부 쿼리가 참조 불가
-- 연관 스칼라 : 각 행마다 결과가 달라져 외부쿼리 행만큼 실행
SELECT 이름, 부서, 급여,
    (SELECT AVG(급여)
     FROM 직원 e2
     WHERE e2.부서 = e1.부서) as 부서평균
FROM 직원 e1;

-- 비연관 스칼라 : 옵티마이저가 1번만 실행
SELECT 이름, 급여,
    (SELECT AVG(급여) FROM 직원) as 전체평균
FROM 직원;

 

2) 인라인 뷰 Inline View : FROM 절

  • FROM 절에 오는 서브쿼리
  • 서브쿼리를 임시 테이블처럼 사용
  • 서브쿼리의 별칭/컬럼을 외부 쿼리가 참조가능
SELECT sub.부서, sub.평균급여
FROM (
    SELECT 부서, AVG(급여) as 평균급여
    FROM 직원
    GROUPBY 부서
) sub;

 

3) WHERE 절

  • 서브쿼리 결과의 값만 사용
  • 서브쿼리의 별칭/컬럼을 외부 쿼리가 참조불가.
SELECT 이름
FROM 직원
WHERE 급여 > (SELECT AVG(급여) FROM 직원);

 

4) HAVING, ORDER BY절

SELECT 부서, AVG(급여) as 평균급여
FROM 직원
GROUP BY 부서
HAVING AVG(급여) > (SELECT AVG(급여) FROM 직원);

서브쿼리는 외부쿼리의 컬럼/별칭을 사용가능하다.

 

 

구분 서브쿼리 → 외부쿼리  외부쿼리 → 서브쿼리 참조
연관 서브쿼리 ⭕ 가능 ❌ 불가
비연관 서브쿼리 ❌ 불가 ❌ 불가
스칼라 서브쿼리 (SELECT절) ⭕ 가능 (연관일 때) ❌ 불가
인라인 뷰 (FROM절) ❌ 불가 ⭕ 가능 (별칭/컬럼 참조 가능)
WHERE절 서브쿼리 ⭕ 가능 (연관일 때) ❌ 불가
HAVING절 서브쿼리 ⭕ 가능 (연관일 때) ❌ 불가

블로그의 정보

우와한개발자 님의 블로그

우와한개발자

활동하기