[Oracle] Join vs Subquery 차이

limlim·2023년 4월 10일
0

Oracle

목록 보기
1/4
  • Join vs Subquery의 차이는 무엇인가?

sql을 공부하면서 join, subquery를 둘 다 사용해보았다.
성능적으로 어떤게 더 나은가? 가 궁금해졌다.
가독성은 subquery가 좋았는데 나중에 조회할 데이터가 많아졌을 때 성능이 떨어지지 않을까 생각이 들었다.

그래서 관련 자료를 한번 찾아보았다.
자료들을 찾아보니 join, subquery 둘 다 성능적으로 좋다고 할 수는 없으나 경우에 따라 어떤 경우에는 subquery가 좋을 수 있고, 어떤 경우에는 join이 좋을 수도 있다고 한다. 그래서 이걸 파악하기 위해서는 실무에서 많은 쿼리문을 접해봐야 될 것 같다.
+) join은 통계성 데이터에 subquery는 한 테이블에서 하나만 가지고 오고 싶을 때 주로 사용한다고 한다.

그리고 까먹지 않기 위해 아래 내용을 정리해보았다.

1. 조인(join)

  • 두 개 이상의 테이블에 있는 컬럼의 값을 한번에 가져오기 위해 사용하는 것이 조인

  • select 컬럼명 from 테이블1, 테이블2;

  • 두 개 이상의 테이블을 조인하게 되면 다대다의 관계로 가져오기 때문에

  • 테이블1의 로우의 수 x 테이블2의 로우의 수 만큼 로우를 가져오게 된다.

  • 두 개 이상의 테이블에서 가져온 결과 중에 정확한 결과면 가져오기 위해 공통 부분을 이용한 조건문이 반드시 필요함

  • 현업에서 많이 사용함

  • 대표적으로 Inner Join, Outer Join, Self Join이 있음

-- 사원 테이블(emp)과 부서 테이블(dept)을 join함
select * from emp; // 14개 행

select * from dept; // 4개 행

select * from emp, dept; // 56개 행

select * 
from emp a1, dept a2
where a1.deptno = a2.deptno;

-- 사원의 사원번호, 이름, 근무부서 이름을 가져온다.
select a1.empno, a1.ename, a2.dname
from emp a1, dept a2
where a1.deptno = a2.deptno;

-- 사원의 사원번호, 이름, 근무지역을 가져온다.
select a1.empno, a1.ename, a2.loc
from emp a1, dept a2
where a1.deptno = a2.deptno;

-- DALLAS에 근무하고 있는 사원들의 사원번호, 이름, 직무를 가져온다.
select a1.empno, a1.ename, a1.job
from emp a1, dept a2
where a1.deptno = a2.deptno and a2.loc = 'DALLAS';

-- SALES 부서에 근무하고 있는 사원들의 급여 평균을 가져온다.
select avg(a1.sal)
from emp a1, dept a2
where a1.deptno = a2.deptno and a2.dname = 'SALES';

-- 1982년에 입사한 사원들의 사원번호, 이름, 입사일, 근무부서 이름을 가져온다.
select a1.empno, a1.ename, a1.hiredate, a2.dname
from emp a1, dept a2
where a1.deptno = a2.deptno and a1.hiredate between '1982-01-01' and '1982-12-31';

-- 각 사원들의 사원번호, 이름, 급여, 급여등급을 가져온다.
select a1.empno, a1.ename, a1.sal, a2.grade
from emp a1, salgrade a2
where a1.sal between a2.losal and a2.hisal;

-- SALES 부서에 근무하고 있는 사원의 사원번호, 이름, 급여등급을 가져온다.
-- join 해야할 테이블이 3개
select a1.empno, a1.ename, a2.grade 
from emp a1, salgrade a2, dept a3
where a1.sal between a2.losal and a2.hisal and a1.deptno = a3.deptno 
      and a3.dname = 'SALES';

-- 각 급여 등급별 급여의 총합과 평균, 사원의 수, 최대급여, 최소급여를 가져온다.
select sum(a1.sal), trunc(avg(a1.sal)), count(a1.sal), max(a1.sal), min(a1.sal)
from emp a1, salgrade a2
where a1.sal between a2.losal and a2.hisal
group by a2.grade;

-- 급여 등급이 4등급인 사원들의 사원번호, 이름, 급여, 근무부서이름, 근무지역을 가져온다.
select a1.empno, a1.ename, a1.sal, a3.dname, a3.loc
from emp a1, salgrade a2, dept a3
where a1.sal between a2.losal and a2.hisal and a1.deptno = a3.deptno
      and a2.grade = 4;

2. Self Join, Outer Join

  • Self Join : 같은 테이블을 두 번 이상 조인하는 것을 의미함
-- SMITH 사원의 사원번호, 이름, 직속상관 이름을 가져온다.
-- a1 : SMITH 사원의 정보
-- a2 : 직속상관의 정보
select a1.empno, a1.ename, a2.ename
from emp a1, emp a2
where a1.mgr = a2.empno and a1.ename = 'SMITH';

-- FORD 사원 밑에서 일하는 사원들의 사원번호, 이름, 직무를 가져온다.
-- a1 : FORD의 정보
-- a2 : 부하 직원의 정보
select a2.empno, a2.ename, a2.job
from emp a1, emp a2
where a1.empno = a2.mgr and a1.ename = 'FORD';

-- SMITH 사원의 직속상관과 동일한 직무를 가지고 있는 사원들의 사원번호, 이름, 직무를 가져온다.
-- a1 : SMITH 사원의 정보
-- a2 : SMITH의 직속상관 정보
-- a3 : 직속상관과 동일한 직무를 가지고 있는 사원의 정보
select a3.empno, a3.ename, a3.job
from  emp a1, emp a2, emp a3
where a1.mgr = a2.empno and a2.job = a3.job and a1.ename = 'SMITH';
  • Outer Join : 조인 조건에 해당하지 않기 때문에 결과에 포함되지 않는 로우까지 가져오는 조인
-- 각 사원의 이름, 사원번호, 직장상사 이름을 가져온다. 단 직속상관이 없는 사원도 가져온다.
-- a1 : 각 사원의 정보
-- a2 : 직장상사의 정보
select a1.ename, a1.empno, a2.ename
from emp a1, emp a2
where a1.mgr = a2.empno(+); // null인 부분까지 포함시킬 경우 (+) 해줌, 부족한 부분에 +

-- 모든 부서의 소속 사원의 근무부서명, 사원번호, 사원이름, 급여를 가져온다.
select a2.dname, a1.empno, a1.ename, a1.sal
from emp a1, dept a2
where a1.deptno(+) = a2.deptno; // null인 부분까지 포함시킬 경우 (+) 해줌, 부족한 부분에 +

3. 서브쿼리(sub query)

  • 쿼리문 안에 들어가는 쿼리문을 서브쿼리라고 함
  • 쿼리문 작성시 사용되는 값을 다른 쿼리문을 통해 구해야 할 경우 사용함
-- SCOTT 사원이 근무하고 있는 부서의 이름을 가져온다.
select dname
from dept
where deptno = (select deptno
                from emp
                where ename = 'SCOTT');

select a2.dname
from emp a1, dept a2
where a1.deptno = a2.deptno and a1.ename = 'SCOTT';

-- SMITH와 같은 부서에 근무하고 있는 사원들의 사원번호, 이름, 급여액, 부서이름을 가져온다.
select a1.empno, a1.ename, a1.sal, a2.dname
from emp a1, dept a2
where a1.deptno = a2.deptno and a1.deptno = (select deptno
                                             from emp
                                             where ename = 'SMITH');

-- MARTIN과 같은 직무를 가지고 있는 사원들의 사원번호, 이름, 직무를 가져온다.
select empno, ename, job
from emp
where job = (select job
             from emp
             where ename = 'MARTIN');

-- ALLEN과 같은 직속상관을 가진 사원들의 사원번호, 이름, 직속상관이름을 가져온다.
-- a1 : 사원의 정보
-- a2 : 직속상관 정보
select a1.empno, a1.ename, a2.ename
from emp a1, emp a2
where a1.mgr = a2.empno and a1.mgr = (select mgr
                                      from emp
                                      where ename = 'ALLEN');

-- WARD와 같은 부서에 근무하고 있는 사원들의 사원번호, 이름, 부서번호를 가져온다.
select empno, ename, deptno
from emp
where deptno = (select deptno
                from emp
                where ename = 'WARD');

-- SALESMAN의 평균 급여보다 많이 받는 사원들의 사원번호, 이름, 급여를 가져온다.
select empno, ename, sal
from emp
where sal > (select avg(sal)
             from emp
             where job = 'SALESMAN');

-- DALLAS 지역에 근무하는 사원들의 평균 급여를 가져온다.
select trunc(avg(sal))
from emp
where deptno = (select deptno
                from dept
                where loc = 'DALLAS');

-- SALES 부서에 근무하는 사원들의 사원번호, 이름, 근무지역을 가져온다.
select a1.empno, a1.ename, a2.loc 
from emp a1, dept a2
where a1.deptno = a2.deptno and a1.deptno = (select deptno
                                             from dept
                                             where dname = 'SALES');

-- CHICAGO 지역에 근무하는 사원들 중 BLAKE이 직속상관인 사원들의 사원번호, 이름, 직무를 가져온다.
select empno, ename, job
from emp
where mgr = (select empno 
             from emp 
             where ename = 'BLAKE') 
      and deptno = (select deptno
                    from dept
                    where loc = 'CHICAGO');

4. 결과가 하나 이상인 서브쿼리

  • 서브쿼리를 통해 가져온 결과가 하나 이상인 경우 결과를 모두 만족하거나 결과 중 하나만 만족하거나 해야 하는 경우가 있음

  • 이때 다음과 같은 연산자를 사용하면 됨

    • IN: 서브쿼리의 결과 중 하나라도 일치하면 조건은 참이 된다.

    • ANY, SOME: 서브쿼리의 결과와 하나 이상 일치하면 조건은 참이 된다.

    • ALL: 서브쿼리의 결과와 모두 일치해야 조건은 참이 된다.

-- 3000 이상의 급여를 받는 사원들과 같은 부서에 근무하고 있는 사원의 사원번호, 이름, 급여를 가져온다.
select empno, ename, sal
from emp
where deptno in (select deptno
                 from emp
                 where sal >= 3000);

-- 직무가 CLERK인 사원과 동일한 부서에 근무하고 있는 사원들의 사원번호, 이름, 입사일을 가져온다.
select empno, ename, hiredate
from emp
where deptno in (select deptno
                 from emp
                 where job = 'CLERK');

-- KING을 직속상관으로 가지고 있는 사원들이 근무하고 있는 근무 부서명, 지역을 가지고 온다.
select dname, loc
from dept
where deptno in (select deptno
                from emp
                where mgr = (select empno
                             from emp
                             where ename = 'KING'));

-- CLERK들의 직속상관의 사원번호, 이름, 급여를 가져온다.
select empno, ename, sal
from emp
where empno in (select mgr
                from emp
                where job = 'CLERK');

-- 각 부서별 급여 평균보다 더 많이 받는 사원의 사원번호, 이름, 급여를 가져온다.
select empno, ename, sal
from emp
where sal > all (select avg(sal)
                 from emp
                 group by deptno);


-- 각 부서별 급여 평균보다 더 많이 받는 사원의 사원번호, 이름, 급여를 가져온다.
select empno, ename, sal
from emp
where sal > all (select avg(sal)
                 from emp
                 group by deptno);
                 
select empno, ename, sal
from emp
where sal > (select max(avg(sal))
                 from emp
                 group by deptno);

-- 각 부서별 급여 최저치보다 많이 받는 사원들의 사원번호, 이름, 급여를 가져온다.
select empno, ename, sal
from emp
where sal > all (select min(sal)
                 from emp
                 group by deptno);

select empno, ename, sal
from emp
where sal > (select max(min(sal))
                 from emp
                 group by deptno);

-- SALESMAN 보다 급여를 적게 받는 사원들의 사원번호, 이름, 급여를 가져온다.
select empno, ename, sal
from emp
where sal < all (select sal
                 from emp
                 where job = 'SALESMAN');

select empno, ename, sal
from emp
where sal < (select min(sal)
                 from emp
                 where job = 'SALESMAN');

-- 각 부서별 최저 급여 액수보다 많이 받는 사원들이 사원번호, 이름, 급여를 가져온다.
select empno, ename, sal
from emp
where sal > any (select min(sal)
                 from emp
                 group by deptno);

-- DALLAS에 근무하고 있는 사원들 중 가장 나중에 입사한 사원의 입사 날짜보다 더 먼저 입사한 사원들의 사원번호, 이름, 입사일을 가져온다.
select empno, ename, hiredate
from emp
where hiredate < any (select hiredate
                      from emp
                      where deptno = (select deptno
                                      from dept
                                      where loc = 'DALLAS'));
profile
不怕慢,只怕站 개발자

0개의 댓글