SQL Cook: 제3 장 복습

0

SQL_COOK

목록 보기
15/35
post-thumbnail

UNION

  • 합집합 연산이다.
  • 결과셋을 포갤 때(쌓을 때) 사용한다.
  • 몇 개의 테이블을 UNION하든, 중복된 데이터도 모두 쌓는다.
  • 단, 조회하는 테이블의 칼럼의 자료형은 동일해야 한다
    • 구문
      /* col_a와 col_b와 col_c의 자료형은 반드시 동일해야 한다 */
      select col_a from tbl_a 
      union all
      select col_b from tbl_b
      union all
      select col_c from tbl_c
      ...
  • 중복된 내용을 제거하고 싶다면 UNION을 사용한다
  • UNION ALLDISTINCT를 함꼐 사용하면, UNION과 같이 작동한다
    그러나 반드시 필요한 경우가 아닌 이상 권장되지 않는다
  • DISTINCT는 중복된 내용을 날리고 하나만 반환한다

JOIN

  • 공통된 칼럼 또는 공통된 값을 가지는 칼럼을 기준으로 테이블을 합친다
  • 여러 테이블에서 행을 반환할 때 사용한다
  • 테이블 간, 공통된 행을 찾는 경우에 사용한다

INNER JOIN

  • INNER 키워드는 선택사항이다
  • 집합 연산의 교집합을 생각한다
    • 특정 칼럼의 값이 같을 때, 각 테이블에서 해당 칼럼의 값에 해당하는 행만 반환한다
      select e.ename, d.loc
      	from emp e inner join dept d
      	on e.deptno = d.deptno
      'DEPTNO'의 값이 같은 행들이 반환된다.


두 테이블의 공통된 행 찾기

'EMP'테이블과 아래의 테이블이 존재한다고 가정하겠다.

+--------+-------+------+
| ename  | job   | sal  |
+--------+-------+------+
| SMITH  | CLERK |  800 |
| ADAMS  | CLERK | 1100 |
| JAMES  | CLERK |  950 |
| MILLER | CLERK | 1300 |
+--------+-------+------+

'ENAME', 'JOB', 'SAL'은 모두 'EMP' 테이블에 들어있는 값이다.
공통으로 가지고 있는 열이 세 개나 있다.
이럴 때 JOIN은 어떻게 써야할까?

  • 올바른 결과를 반환하는 데 필요한 모든 열의 테이블을 JOIN한다

    select e.empno, e.ename, e.job, e.sal, e.deptno 
    	from emp e join v 
    	on e.ename = v.ename 
    	and e.job = v.job 
    	and e.sal = v.sal;
    
  • 오라클에서는 다음과 같이 사용한다

    select empno, ename, job, sal, deptno
      from emp
      where (ename, job, sal) in (
          select ename, job, sal from emp
          intersect
          select ename, job, sal from V)

    'EMP' 테이블과 'V'테이블에서 'ENAME', 'JOB', 'SAL'칼럼이 공통값을 가지는 부분을 조회한다. 외부쿼리의 SELECT 구문에서 조회해둔 데이터 중 INTERSECT구문의 결과셋과 'EMP'테이블을 비교하여, 또다시 'ENAME', 'JOB', 'SAL'칼럼이 공통값을 가지는 부분으로 조회 조건을 제한한다.

    • INTERSECT는 집합 연산이며, 공통된 행만을 반환하는 것에 주의힌다
    • 중복되는 행은 반환하지 않으므로, 손실되는 데이터가 생길 수 있다

한 테이블에서 다른 테이블에 존재하지 않는 '값' 검색하기

'EMP' 테이블과 'DEPT' 테이블 모두 'DEPTNO'를 가지고 있다.
그러나 'EMP' 테이블의 'DEPTNO' 칼럼에는 없는 값이 'DEPT' 테이블의 'DEPTNO'에는 있을 수도 있다.

이런 값을 찾을 때 다음과 같은 방법을 사용한다.

Oracle

MINUS를 사용한다.

select deptno from dept
minus
select deptno from emp
>>
DEPTNO
40

반대로 하면?
아무 것도 출력되지 않는다.
말 그대로 집합 연산이므로, 집합으로 생각해보면 바로 알 수가 있다.

Maria

  1. 서브쿼리를 사용하여 'EMP' 테이블의 모든 'DEPTNO'를 반환한다
  2. 그 후 그 결과셋에 포함되지 않는 'DETPNO'를 찾는 조건 검사를 수행한다(WHERE절)
select deptno 
	from dept
    where deptno not in (select deptno from emp)
>>
DEPTNO
40

이는 당연하게도 Oracle에서도 동일하게 작동한다.

단, 이 경우에 NULL값을 신경써야 한다.
만약 위 쿼리에서 'EMP'테이블의 'DEPTNO'칼럼 값에 NULL이 포함되어 있다면 쿼리는 행을 반환하지 않는다.

FALSE or NULLNULL이기 때문이다.

이 문제를 방지하기 위해 NOT EXISTS와 함께 서브쿼리를 사용한다

select d.deptno
	from dept d
    where not exists(
    	select 1
        from emp e
        where d.deptno = e.deptno
        )
  1. 외부쿼리의 FROM절이 실행되면서 alias d 생성
  2. 외부쿼리의 WHERE절이 실행, 외부쿼리의 'WHERE'절에 종속된 내부쿼리가 실행
  3. 'DEPT' 테이블의 'DEPTNO' 값과 'EMP' 테이블의 'DEPTNO'가 일치하는 경우가 아닐 때
    해당 'DEPTNO'의 값을 'DEPT' 테이블에서 반환한다
  4. 즉, 'EMP' 테이블의 'DETPNO'칼럼 값 중에 'DEPT' 테이블의 'DEPTNO' 칼럼 값이 존재하지 않을 때, 'DEPT' 테이블의 'DEPTNO' 칼럼 값을 반환한다

다른 테이블의 행과 일치하지 않는 '행' 검색하기

앞과 묘하게 다르다. 없는 '값'을 검색한 앞과 달리 이번엔 '행'을 검색한다.

select d.*
	from dept d left join emp e
    on d.deptno = e.deptno
    where e.deptno is null
>>
+--------+------------+--------+
| deptno | dname      | loc    |
+--------+------------+--------+
|     40 | OPERATIONS | BOSTON |
+--------+------------+--------+
  1. 'DEPTNO'가 존재하고, 동일한 경우에 OUTTER JOIN을 실행한다
  2. 'DEPT' 테이블에는 존재하지만, 'EMP' 테이블에는 존재하지 않는 행의 값은 NULL처리
  3. NULL처리 된 값들만 모아주면, 'DEPT' 테이블에는 있지만 'EMP' 테이블에는 없는 행이 반환된다

  1. 5장까지를 요약해봤다.

0개의 댓글