서브쿼리

2 분 소요

서브쿼리 종류

  • 일반 서브쿼리 = WHERE 절에
  • 인라인 뷰 = FROM절에 위치
  • 스칼라 쿼리 = SELECT 절에 위치
  • 서브쿼리를 사용하면 내부적으로 쿼리 블럭이 생성되므로 느려질 수 있음, 되도록 join을 사용하는 것이 좋음.
  • JOIN을 먼저 하기 보다는 서브쿼리로 GROUP BY 결과를 먼저 도출하여 JOIN하는 것이 이상적임,
    하지만 그럴수 없는경우도 생김

인라인 뷰(FROM절)

인라인 뷰 실습

  SELECT * FROM EMP;
  SELECT * FROM DEPT;
  
  SELECT D.DEPTNO, D.DNAME, E.SAL
  FROM DEPT D, (
              SELECT DEPTNO, MAX(SAL) SAL 
              FROM EMP
              GROUP BY DEPTNO
              ) E
  WHERE E.DEPTNO = D.DEPTNO;

인라인 뷰 실습2

  • student 테이블과 department 테이블을 사용하여 학과별로 학생들의 최대 키와 최대 몸무게, 학과이름을 출력하세요.
  • 조건별 그룹을 만드려면 student 테이블을 인라인 뷰로 잡아야한다…
  • 키워드 (학과별 학생들의 키와 몸무게) 이거는 student 테이블에 키와 몸무게가 있기 때문에…
  SELECT D.DNAME, S.HEIGHT, S.WEIGHT
  FROM DEPARTMENT D,(                 
                      SELECT DEPTNO1 DEPTNO,MAX(HEIGHT) HEIGHT, MAX(WEIGHT) WEIGHT
                      FROM STUDENT
                      GROUP BY DEPTNO1
                      ) S
WHERE D.DEPTNO = S.DEPTNO;

인라인 뷰 실습3

  SELECT S1.GRADE, S1.NAME, S1.HEIGHT, S2.HEIGHT
  FROM STUDENT S1,(                 
                      SELECT GRADE,AVG(HEIGHT) HEIGHT
                      FROM STUDENT
                      GROUP BY GRADE
                      ) S2
  WHERE
        S1.GRADE = S2.GRADE AND
        S1.HEIGHT > S2.HEIGHT
  ORDER BY S1.GRADE;

일반 서브쿼리(where절)

서브쿼리(where절) 실습 1

  select S.name, D.DNAME
  from STUDENT S, DEPARTMENT D
  where
      S.deptno1 = ( select deptno1
                  from STUDENT
                  where name = 'Anthony Hopkins')
      and S.deptno1 = D.deptno;

서브쿼리(WHERE절) 실습 2

  select NAME, WEIGHT
  FROM STUDENT
  WHERE WEIGHT > (
              select avg(WEIGHT)
              FROM STUDENT
              WHERE deptno1 = 201
              group by deptno1
              );

다중행 sub Query 실습 1

  SELECT empno, name, deptno
  from emp2
  where deptno IN(
                  select dcode
                  from dept2
                  where area = 'Pohang Main Office'
                  );

다중행 sub Query 실습 2

  select name, position, to_char(pay, '999,999,999,999') salary
  from emp2
  where pay > (
              SELECT min(pay)
              from emp2
              where position = 'Section head'
              group by position
              );

다중행 sub Query 실습 3

  select E.name,D.dname,to_char(E.pay, '$999,999,999,999') salary
  from emp2 E, dept2 D
  where E.deptno = D.dcode
      and E.pay < all(
                  SELECT avg(pay)
                  from emp2
                  group by deptno
                  );

다중열 sub Query 실습 1

  • 결과 값이 두개 이상의 컬럼을 반환하는 subquery
  • and 로 두개로 빼지말고 무조건 2개 컬럼을 동시 비교하는 문으로 짜야한다!!(다른결과)
  select empno, ename, sal, deptno
  from emp
  where (sal, deptno) in (
                          select SAL, DEPTNO
                          from emp
                          where
                              deptno = 30
                              AND comm > 0
                          );

다중열 sub Query 실습 2

  SELECT GRADE, NAME, WEIGHT
  FROM STUDENT
  WHERE (GRADE, WEIGHT) IN(
                          SELECT GRADE, MAX(WEIGHT) 
                          FROM STUDENT
                          GROUP BY GRADE
                          );

상호연관 서브쿼리 실습 1

  • 키워드 “자기자신의 직급….(여러건)”
  • 내부적으로 exists로 풀린다… 그러므로 차라리 exists로 푸는게 맞는거 같음…
  SELECT NAME 사원이름, POSITION 직급, PAY 급여
  FROM emp2 E1
  WHERE  pay >= (
                  select avg(pay)
                  from emp2 E2
                  where E1.position = E2.position
                  );

스칼라 서브쿼리(SELECT절)

  • 데이터 row 갯수만큼 쿼리블럭이 생성되므로 엄청 느려질수 있음… 조심해야함….
  • “캐싱된다” = 중복된 여러건을 내부적으로 1건으로 처리 한다는 의미
  • 배치업무에서는 절대로 사용되어서는 안되는 스칼라 서브쿼리….
  • 데이터가 없는경우: null 데이터로 표시 해준다 /// 2건이상 나오는 경우: 에러가 발생…

스칼라 쿼리 실습 1

  • dept 테이블을 모체로 잡고, emp테이블 그룹함수를 써서 최대값을 구할 수 있음(대입 하는 개념)
  select d.deptno, d.dname, (
                              select max(sal)
                              from emp
                              where deptno = d.deptno
                            ) sal
  from  dept d;

=> 아래와 같이 스칼라쿼리는 쿼리 튜닝을 해주어야 한다.

  select d.deptno deptno, d.dname, max(e.sal)
  from dept d left outer join emp e  --outer join으로 바꿈... null값을 찾기위해
  on d.deptno = e.deptno
  group by d.deptno, d.dname;

댓글남기기