CS - 강의, 서적/[SQLD] 홍쌤의 데이터랩

[SQLD] 2-9. 서브 쿼리 (스칼라 서브 쿼리, 인라인 뷰, WHERE절 서브 쿼리 다수)

SH3542 2024. 9. 18. 21:08

[홍쌤의 데이터랩, SQLD n과목 완벽 정리] 영상를 개인이 정리하여 [원작자의 허가 이후] 올린 글이며,

[개인이 추가로 정리한 내용]이 포함되어 있습니다.

 

 

 
 

홍쌤의 데이터랩

[개정판] SQLD n과목 완벽 정리

https://www.youtube.com/watch?v=rdfHFnqVoRw

 

 


 

 

목차

 

    서브 쿼리 (Sub Query)

    - 쿼리 안에 포함되어있는 또 다른 쿼리

    - 반드시 괄호로 묶어야 함

    - GROUP BY절에 사용 불가

     

    서브 쿼리의 분류

    1. 동작 방식에 따른 분류

    1) UN-CORRNLATED(비연관) 서브 쿼리

    - 서브 쿼리가 메인쿼리의 컬럼을 가지고 있지 않은 형태

    - 메인쿼리에 서브 쿼리의 결과 값을 제공하기 위해 사용

     

    2) CORRNLATED(연관) 서브 쿼리

    - 서브 쿼리가 메인쿼리의 컬럼을 가지고 있는 형태

    - 일반적으로 메인쿼리의 수행 이후, 서브 쿼리에서 조건 확인을 위해 사용

     

    2. 위치에 따른 분류

    1) 스칼라 서브 쿼리

    - SELECT절에 사용하는 서브 쿼리

    - 주로 서브 쿼리 결과를 하나의 컬럼 처럼 사용하기 위해 사용

    => 단일행 서브 쿼리 형태여야 함

    - 조인의 대체 연산

    - 스칼라 서브 쿼리를 사용한 JOIN 처리시, OUTER JOIN이 기본 (값이 없더라도 생략되지 않고 NULL로 출력)

     

    e.g.

     

    1) SELF JOIN - LEFT OUTER JOIN 형태

    SELECT E1.ENAME AS 사원,

                   (SELECT E2.ENAME

                    FROM EMP E2

                    WHERE E1.MGR = E2.EMPNO) AS 관리자

    FROM EMP E1;

     

    사원의 관리자가 없는 (NULL인)경우, 

    WHERE E1.MGR = E2.EMPNO 조건에서 조건을 만족하지 않으므로 INNER JOIN 형태를 띄지만,

    메인 쿼리문에서 다시 포함시키므로 OUTER JOIN 동작과 유사해짐

    정확히는, 메인쿼리가 왼쪽에 존재하므로 LEFT OUTER JOIN 동작과 유사해짐 

     

    2) 인라인 뷰

    - FROM절에 사용하는 서브 쿼리

    - 주로 서브 쿼리 결과를 테이블처럼 사용하기 위해 사용 (메인 쿼리 테이블과의 JOIN)

     - 테이블명이 존재하지 않으므로 JOINAlias 필요

    - WHERE절 서브 쿼리와 다르게 서브 쿼리 결과를 메인 쿼리의 모든 절에 사용할 수 있음

    - 모든 연산자 사용 가능

     

    1) 에러 구문 - 단일행과 그룹의 대소 비교

    SELECT *

    FROM EMP E, (SELECT AVG(SAL) AS AVG_SAL

                              FROM EMP

                              GROUP BY DEPTNO) I

    WHERE E.SAL > I.AVG_SAL; -- error

     

    2) 올바른 구문 - JOIN 활용

    SELECT *

    FROM EMP E, (SELECT DEPTNO , AVG(SAL) AS AVG_SAL

                              FROM EMP

                              GROUP BY DEPTNO) I

    WHERE E. DEPTNO = I. DEPTNO

    AND E.SAL > I.AVG_SAL;  -- 위 구문에서 필요했던 조건

     

    3) WHERE절 서브 쿼리

    - 특별한 명칭 없음

    - 주로 비교 상수 자리에 값을 전달하기 위해로 사용 (상수항 대체)

    - 리턴 데이터의 형태에 따라 단일행/다중행/다중컬럼/상호연관 서브 쿼리로 구분


    3-1) 단일 행 서브 쿼리

    - 서브 쿼리 결과로 단일 행이 리턴

    - 비교연산자 {=, <> (같지 않다), >, >=, <, <= 등}와 사용

     

    e.g.

    SELECT *

    FROM T1

    WHERE PRICE > (SELECT PRICE

                                  FROM T2

                                  WHERE NO = 3);


    3-2) 다중 행 서브 쿼리

    - 서브 쿼리 결과로 다중 행이 리턴

    - 비교 연산자와 사용 불가능

    - 단일 결과(행)로 바꾸거나, 다중행 서브 쿼리 연산자와 {IN, ANY, ALL 등}사용

     

    해당 식들은 WHERE NO = IN(1,2,3)과 같이 단일행으로 처리 됨

    > ALL() : 모든 원소 보다 큰

    > ALL(1,2,3) : 3(최댓값)보다 큰

    < ALL() : 모든 원소 보다 작은

    <ALL(1,2,3) : 1(최솟값)보다 작은

    > ANY() : 원소 중 어떤 값 보다 큰

    >ANY(1,2,3) : 1(최솟값)보다 큰

    < ANY() : 원소 중 어떤 값 보다 작은

    <ANY(1,2,3) : 3(최댓값)보다 작은

     

    e.g.

    1) 다중행 -> 단일행 서브 쿼리로 변경

    SELECT *

    FROM T1

    WHERE PRICE > (SELECT MIN(PRICE)

                                  FROM T2

                                WHERE CATEGORY = 'BOOK');

     

    2) 다중행 서브 쿼리 연산자 사용

    SELECT *

    FROM T1

    WHERE PRICE > ANY(SELECT PRICE

                                          FROM T2

                                          CATEGORY = 'BOOK');


    3-3) 다중 컬럼 서브 쿼리

    - 서브 쿼리 결과로 다중 컬럼이 리턴

    - 동등 비교 가능, 대소 비교 전달 불가 (컬럼이 2개 이상이므로, 두 값 동시에 대소비교 불가)

     

    e.g.

     

    1) 부서별 최대 급여

    SELECT DEPTNO, MAX(SAL)

    FROM EMP

    GROUP BY DEPTNO;

     

    해당 쿼리문은 그룹화 이후 집계하기 때문에, SELECT문에 최대 급여자(ENAME) 컬럼 추가 불가능

     

    2) 부서별 최대 급여 및 최대 급여자

    SELECT ENAME, SAL, DEPTNO

    FROM EMP

    WHERE (DEPTNO, SAL) IN (SELECT DEPTNO, MAX(SAL) -- 서브 쿼리에 컬럼이 2개

                                                    FROM EMP

                                                    GROUP BY DEPTNO);


    3-4) 상호 연관 서브 쿼리

    - 메인쿼리와 서브 쿼리의 비교를 수행하는 형태

    - 비교할 집단이나 조건은 서브 쿼리에 명시 (메인쿼리에는 서브 쿼리 컬럼이 정의되지 않았기 때문에 에러)

     

    e.g.

    부서별 평균급여보다 높은 급여를 받는 사원 (대소 비교 필요)

     

    1) 에러 구문 - 다중컬럼 서브 쿼리의 대소비교 수행

    SELECT ENAME, SAL, DEPTNO

    FROM EMP

    WHERE (DEPTNO, SAL) > (SELECT DEPTNO, AVG(SAL) -- 대소 비교 불가

                                                    FROM EMP

                                                    GROUP BY DEPTNO);

     

    2) 올바른 구문 - 상호연관 서브 쿼리 (대소 비교할 컬럼을 메인쿼리, 일치 조건을 서브 쿼리에 전달)

    SELECT ENAME, SAL, DEPTNO

    FROM EMP E1

    WHERE SAL > (SELECT AVG(SAL)

                              FROM EMP E2

                              WHERE E1.DEPTNO = E2.DEPTNO -- 일치 조건

                           -- AND E1.XX = E2.XX => 추가 조건 기입

                              GROUP BY DEPTNO);                       -- GROUP BY절 생략 가능