ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • SQL - SUBQUERY
    DataBase/Oracle 2022. 1. 21. 11:22
    반응형

    SUBQUERY

    • 하나의 SELECT 문장의 절 안에 포함된 또 하나의 SELECT 문장
    • 서브쿼리는 메인쿼리가 실행되기 이전에 한번만 실행된다.
    • 비교연산자의 오른쪽에 기술해야하며, 반드시 괄호로 묶어야 한다.
    • SELECT, FROM, WHERE, HAVING, ORDER BY 절에서 사용할 수 있다.

     

     

    단일행 서브쿼리

     

    • 서브쿼리의 조회 결과 값이 1개의 행일 때
    • 보통 단일행 서브쿼리 앞에는 일반 비교 연산자를 사용한다.
    • >, <, >=, <=, =, !=

     

    -- 단일행 코드
    -- 사원명이 노옹철인 사람의 부서 조회
    SELECT
           DEPT_CODE
      FROM EMPLOYEE
     WHERE EMP_NAME = '노옹철';
     
    -- 부서코드가 D9인 직원을 조회
    SELECT
           EMP_NAME
      FROM EMPLOYEE
     WHERE DEPT_CODE = 'D9';
    
    -- 위의 두 쿼리를 하나로  
    SELECT
           EMP_NAME
      FROM EMPLOYEE
     WHERE DEPT_CODE = (SELECT
                               DEPT_CODE
                          FROM EMPLOYEE
                         WHERE EMP_NAME = '노옹철'
                       );


     

     

    다중행 서브쿼리

     

    • 서브쿼리의 조회 결과 값이 여러개의 행일 때
    • 서브쿼리 앞에서는 일반 비교 연산자를 사용할 수 없다.
    • 다중행 서브쿼리에 사용되는 연산자
      IN      : 여러 개의 결과 값 중에서 메인 쿼리와 한 개라도 일치하는 값이 존재하는지 판별
      ANY   : 여러 개의 결과 값 중에서 메인 쿼리가  개라도 큰 값이 존재하는지 판별
      ALL    : 여러 개의 결과 값이 메인 쿼리가 모두 큰 값인지를 판별
      EXIST : 서브쿼레만 사용하는 연산자로 값이 존재하는지 판별

    IN 연산자 사용

    -- 부서별 최고 급여를 받는 직원의 이름, 직급, 부서, 급여 조회
    SELECT
           E.DEPT_CODE
         , MAX(E.SALARY)
      FROM EMPLOYEE E
     GROUP BY E.DEPT_CODE;
     
    SELECT
           E.EMP_NAME
         , E.JOB_CODE
         , E.DEPT_CODE
         , E.SALARY
      FROM EMPLOYEE E
     WHERE E.SALARY IN (SELECT MAX(E2.SALARY)
                          FROM EMPLOYEE E2
                         GROUP BY E2.DEPT_CODE
                       );

     

     

    ANY 연산자 사용

    -- 대리 직급의 직원들 중에서 과장 직급의 최소 급여보다 많이 받는
    -- 직원의 사번, 이름, 직급명, 급여를 조회하세요
    
    SELECT
           E.EMP_ID
         , E.EMP_NAME
         , J.JOB_NAME
         , E.SALARY
      FROM EMPLOYEE E
      JOIN JOB J ON(E.JOB_CODE = J.JOB_CODE)
     WHERE J.JOB_NAME = '과장';
    
    SELECT
           E.EMP_ID
         , E.EMP_NAME
         , J.JOB_NAME
         , E.SALARY
      FROM EMPLOYEE E
      JOIN JOB J ON(E.JOB_CODE = J.JOB_CODE)
     WHERE J.JOB_NAME = '대리';
    
    
    SELECT
           E.EMP_ID
         , E.EMP_NAME
         , J.JOB_NAME
         , E.SALARY
      FROM EMPLOYEE E
      JOIN JOB J ON(E.JOB_CODE = J.JOB_CODE)
     WHERE J.JOB_NAME = '대리'
       AND E.SALARY > ANY (SELECT
                                  E2.SALARY
                             FROM EMPLOYEE E2
                             JOIN JOB J2 ON(E2.JOB_CODE = J2.JOB_CODE)
                            WHERE J2.JOB_NAME = '과장'
                          );

     

     

    ALL 연산자 사용

    -- 차장 직급의 급여의 가장 큰 값보다 많이 받는 과장 직급의
    -- 사번, 이름, 직급, 급여를 조회하세요
    
    SELECT 
           E.EMP_ID
         , E.EMP_NAME
         , J.JOB_NAME
         , E.SALARY
      FROM EMPLOYEE E
      JOIN JOB J ON(E.JOB_CODE = J.JOB_CODE)
     WHERE J.JOB_NAME = '과장'
       AND E.SALARY >ALL (SELECT E2.SALARY
                            FROM EMPLOYEE E2
                            JOIN JOB J2 ON(E2.JOB_CODE = J2.JOB_CODE)
                           WHERE J2.JOB_NAME = '차장'
                         );

     

     

    EXISTS 사용

    -- 관리자 사번이 EMPLOYEE 테이블에 존재하는 직원에 대한 조회
    SELECT
           E.EMP_ID
         , E.EMP_NAME
         , E.DEPT_CODE
         , E.MANAGER_ID
      FROM EMPLOYEE E
     WHERE EXISTS (SELECT E2.EMP_ID
                     FROM EMPLOYEE E2
                    WHERE E.MANAGER_ID = E2.EMP_ID
                  );

     


     

    다중행, 다중열 서브쿼리

     

    • 서브쿼리의 조회 결과 컬럼의 개수와 행의 개수가 여러 개 일 때

     

    SELECT 
           E.EMP_ID
         , E.EMP_NAME
         , E.JOB_CODE
         , E.SALARY
      FROM EMPLOYEE E
     WHERE (E.JOB_CODE, E.SALARY) IN (SELECT 
                                             E2.JOB_CODE
                                           , TRUNC(AVG(E2.SALARY), -5)
                                        FROM EMPLOYEE E2
                                       GROUP BY E2.JOB_CODE
                                     );


     

     

    다중열 서브쿼리

     

    • 서브쿼리의 조회 결과 컬럼의 개수가 여러 개 일 때

     

    -- 퇴사한 여직원과 같은 부서, 같은 직급에 해당하는
    -- 사원의 이름, 직급, 부서, 입사일을 조회
    
    SELECT
           E.EMP_ID
         , E.EMP_NAME
         , E.DEPT_CODE
         , E.JOB_CODE
      FROM EMPLOYEE E
     WHERE SUBSTR(E.EMP_NO, 8, 1) = 2
       AND E.ENT_YN = 'Y';
       
    -- 다중열을 이용하지 않고 쿼리 작성
    SELECT
           E.EMP_ID
         , E.JOB_CODE
         , E.DEPT_CODE
         , E.HIRE_DATE
      FROM EMPLOYEE E
     WHERE E.DEPT_CODE = (SELECT E2.DEPT_CODE
                            FROM EMPLOYEE E2
                           WHERE SUBSTR(E2.EMP_NO, 8, 1) = 2
                             AND E2.ENT_YN = 'Y'
                         )
       AND E.JOB_CODE = (SELECT E3.JOB_CODE
                            FROM EMPLOYEE E3
                           WHERE SUBSTR(E3.EMP_NO, 8, 1) = 2
                             AND E3.ENT_YN = 'Y'
                         )
       AND E.EMP_ID != (SELECT E4.EMP_ID
                            FROM EMPLOYEE E4
                           WHERE SUBSTR(E4.EMP_NO, 8, 1) = 2
                             AND E4.ENT_YN = 'Y'
                         );
    
    -- 다중열 서브쿼리로 변경
    SELECT
           E.EMP_ID
         , E.JOB_CODE
         , E.DEPT_CODE
         , E.HIRE_DATE
      FROM EMPLOYEE E
     WHERE (E.DEPT_CODE, E.JOB_CODE) = (SELECT E2.DEPT_CODE
                                             , E2.JOB_CODE
                                          FROM EMPLOYEE E2
                                         WHERE SUBSTR(E2.EMP_NO, 8, 1) = 2
                                           AND E2.ENT_YN = 'Y'
                                        )
       AND E.EMP_ID != (SELECT E3.EMP_ID
                          FROM EMPLOYEE E3
                         WHERE SUBSTR(E3.EMP_NO, 8, 1) = 2
                           AND E3.ENT_YN = 'Y'
                       );

     


     

    인라인 뷰(INLINE VIEW)

     

    • FROM 절에서 서브쿼리를 사용(테이블 대신 사용)
    • 서브쿼리가 만든 결과 집합에 대한 출력
    • 인라인뷰를 이용한 TOP-N 분석이 가능하다.(ROWNUM의 이용)

     

    SELECT
           E.EMP_NAME
         , J.JOB_NAME
         , E.SALARY
      FROM (SELECT E2.JOB_CODE
                 , TRUNC(AVG(E2.SALARY), -5) AS JOBAVG
              FROM EMPLOYEE E2
             GROUP BY E2.JOB_CODE
           ) V
       JOIN EMPLOYEE E ON (V.JOBAVG = E.SALARY AND E.JOB_CODE = V.JOB_CODE)    
       JOIN JOB J ON (E.JOB_CODE = J.JOB_CODE)
      ORDER BY J.JOB_NAME;   
      
    SELECT
           V.EMP_NAME
         , V.부서명
         , V.직급이름
      FROM (SELECT EMP_NAME
                 , DEPT_TITLE AS 부서명
                 , JOB_NAME AS 직급이름
              FROM EMPLOYEE E
              LEFT JOIN DEPARTMENT D ON (E.DEPT_CODE = D.DEPT_ID)
              JOIN JOB J ON (E.JOB_CODE = J.JOB_CODE)
            ) V
     WHERE V.부서명 = '인사관리부';

     

     

    인라인뷰를 이용한 ROWNUM의 이용

    -- 행 번호를 ROWNUM을 이용하여 붙임
    -- 행 번호가 붙여진후 ORDER BY 정렬이 이루어 지므로 순서대로 출력이 안됨
    SELECT 
           ROWNUM
         , E.EMP_NAME
         , E.SALARY
      FROM EMPLOYEE E
     ORDER BY E.SALARY DESC;
    
    -- 행 번호 1~5 출력
    -- 인라인뷰를 이용하여 정렬을 한 후 행 번호를 붙임
    SELECT
           ROWNUM
         , V.EMP_NAME
         , V.SALARY
      FROM (SELECT E.*
              FROM EMPLOYEE E
             ORDER BY E.SALARY DESC
           ) V
     WHERE ROWNUM <= 5;
    
    -- 6~10까지 조회(잘못 된 예)
    SELECT
           ROWNUM 
         , V.EMP_NAME
         , V.SALARY
      FROM (SELECT E.*
              FROM EMPLOYEE E
             ORDER BY E.SALARY DESC
            ) V
     WHERE ROWNUM BETWEEN 6 AND 10;
    
    -- 6위부터 10위까지 조회
    SELECT
           V2.RNUM
         , V2.EMP_NAME
         , V2.SALARY
      FROM (SELECT
                   ROWNUM RNUM
                 , V.EMP_NAME
                 , V.SALARY
              FROM (SELECT E.*
                      FROM EMPLOYEE E
                     ORDER BY E.SALARY DESC
                   ) V
           ) V2
     WHERE RNUM BETWEEN 6 AND 10;

     


     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

    반응형

    'DataBase > Oracle' 카테고리의 다른 글

    SQL - 테이블 생성(CREATE) 및 제약 조건(Constraint)  (0) 2022.01.26
    SQL - RANK, DENSE_RANK  (0) 2022.01.22
    SQL - JOIN  (0) 2022.01.20
    SQL - SET OPERATION  (0) 2022.01.20
    SQL - ROLLUP, CUBE, GROUPING, GROUPING SETS  (0) 2022.01.20

    댓글

Designed by Tistory.