예를 들어 부서값이 10인 모든 사원명과 각 사원의 부서위치 정보를 함께 표시하려하지만, 해당 데이터는 별도의 테이블에 저장되어 있다.
select e.ename, d.loc
from emp e, dept d
where e.deptno = de.deptno
and e.deptno = 10
>>
ENAME LOC
KING NEW YORK
CLARK NEW YORK
MILLER NEW YORK
이는 JOIN
의 한 가지 형태로, 더 정확하게는 내부 JOIN(INNER JOIN
)의 한 형태인 동등 JOIN(EQUI-JOIN
)이다.
개념적으로, JOIN의 결과셋은 다음과 같이 FROM
절에 나열된 테이블에서 '데카르트 곱' 즉, '가능한 모든 행 조합'을 우선 생성하여 만들어진다.
무슨 말이냐 하면
select e.ename, d.loc
from emp e, dept d
where e.deptno = de.deptno
# (위의 쿼리에서 and 자리)
일단 이까지만 돌려서 테이블을 생성한다는 뜻이다. (FROM
절에 나열된 테이블부터 먼저 생성된다는 뜻)
이후 WHERE
절의 식에서 결과셋을 제한하게 된다.
위 쿼리의 대체 해법은 명시적으로 JOIN
절을 사용하는 것이다.
이 때,
INNER
키워드는 선택사항이다.
즉,JOIN
이라고만 써도INNER JOIN
과 같은 결과셋을 반환한다는 뜻이다.
select e.ename, d.loc
# INNER JOIN이므로 두 칼럼의 값이 같은 행만 불러온다
from emp e inner join dept d
# 어떤 칼럼? 이에 대한 정보를 on에 써준다
on e.deptno = d.deptno
# 마지막으로 칼럼의 값을 조건으로 넣어준다
where e.deptno = 10
WHERE
절 대신 FROM
절에 JOIN식을 사용하려면 JOIN
절을 사용한다.
다음의 뷰 V를 예로 들어 살펴본다.
create view V
as
select ename, job, sal
from emp
where job = 'clerk';
select * from V;
>>
+--------+-------+------+
| ename | job | sal |
+--------+-------+------+
| SMITH | CLERK | 800 |
| ADAMS | CLERK | 1100 |
| JAMES | CLERK | 950 |
| MILLER | CLERK | 1300 |
+--------+-------+------+
view V는 직무가 'clerk'인 사원들의 정보를 반환하지만, 가능한 모든 'EMP' 테이블의 열은 표시하진 않는다.
이 때 view V의 행과 일치하는 'EMP' 테이블의 모든 사원의 'EMPNO', 'ENAME', 'JOB', 'SAL' 및 'DEPTNO'를 반환하려 고한다.
SELECT
절에 집어넣는다ON
에 동일 칼럼 조건을 명시해준다/* 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;
>>
+-------+--------+-------+------+--------+
| empno | ename | job | sal | deptno |
+-------+--------+-------+------+--------+
| 7369 | SMITH | CLERK | 800 | 20 |
| 7876 | ADAMS | CLERK | 1100 | 20 |
| 7900 | JAMES | CLERK | 950 | 30 |
| 7934 | MILLER | CLERK | 1300 | 10 |
+-------+--------+-------+------+--------+
/* WHERE절에서 처리 */
select e.empno, e.ename, e.job, e.sal, e.deptno
from emp e, v
where e.name = v.name
and e.job = v.job
and e.sal = v.sal
>>
+-------+--------+-------+------+--------+
| empno | ename | job | sal | deptno |
+-------+--------+-------+------+--------+
| 7369 | SMITH | CLERK | 800 | 20 |
| 7876 | ADAMS | CLERK | 1100 | 20 |
| 7900 | JAMES | CLERK | 950 | 30 |
| 7934 | MILLER | CLERK | 1300 | 10 |
+-------+--------+-------+------+--------+
Oracle Live SQL에서 Oracle의 INTERSECT
를 사용해보고 싶은데 되질 않아서 답답했는데, 알고보니 Oracle에서는 WHERE
절의 조건을 쓸 때 대소문자를 구별한다.
참고로 Maria는 그런 거 안 한다...
# 그러고 나서 명시된 칼럼들을 포함하여 가져온다
select empno, ename, job, sal, deptno
from emp
# 그 행들에 대해 아래의 칼럼세트만 뽑아낸다
where (ename, job, sal) in (
# FROM이 돌아가고 나면 WHERE절이 돌아가는데
# emp 테이블에서 가져온 칼럼들과
select ename, job, sal from emp
# 공통된 행들만 가져온다
intersect
# v에서 가져온 칼럼들을 비교해서
select ename, job, sal from v)
순서대로 보자면 일단
select ename, job, sal from emp
intersect
select ename, job, sal from v
>>
ENAME JOB SAL
ADAMS CLERK 1100
JAMES CLERK 950
MILLER CLERK 1300
SMITH CLERK 800
이렇게 가져온다.
ADAMS, JAMES, MILLER, SMITH가 INTERSECT
의 반환 결과다.
이 상태에서 SELECT
절에서 명시한 나머지 칼럼들(ADAMS, JAMES, MILLER, SMITH에 대한)을 붙이는 것이다.
INTERSECT
는 집합 연산이며, 두 행 소스 중에 공통된 행을 반환한다. 따라서 같은 데이터 유형을 가진 항목 수를 비교해야 한다.
집합 연산으로 작업할 때, 기본적으로 중복 행은 반환하지 않기 때문이다.
즉, 중복으로 인해 버려지는 데이터가 생길 수 있다.
'JOIN'에는 두 가지가 있다.
명시적으로 JOIN
절을 쓸 수도 있고, WHERE
절에서 조건으로 처리할 수도 있다.
FROM
절에서 JOIN을 사용하고 싶다면 JOIN
절을 사용하자
WHERE
절에서 JOIN을 하겠다 하면 조건으로 처리하자
Oracle에서는 INTERSECT
를 지원한다