[Sql] Join
# Join
- 테이블 간 서로 같은 조건의 값을 맵핑하여 조회하는 셀렉트문의 기능
- 데이터의 관리와 유지보수 효율을 높이는데 목적
[예시] Join 관계
# employees & departments


- 직원과 사원 양 테이블에는 department_id라는 동일한 명칭의 컬럼이 존재한다.
- 부서에서 해당 값은 유일 값이며 사원 테이블에서 이 값은 중복이 허용되는 값으로 둘은 서로 동일한 개념의 값이다.
- 이러한 조건 하에서 Join은 양 테이블간의 관계를 묶는 역할을 한다.
# 카다시안의 곱
- 조인의 조건이 생략되었거나 조건 절을 잘못 묶은 경우 발생한다.
- 카다시안의 곱이 발생하면 경우의 수처럼 테이블에 존재하는 모든 행 갯수를 곱한만큼의 결과 값이 반환된다.
- 특히 카다시안의 곱은 시스템 상의 오류가 아니므로 파악이 쉽지 않다.
[예시] 카다시안 곱
- 조인 관계에서 on절의 조건이 없다면 카다시안의 곱이 발생한다.
select e.employee_id, d.department_name from employees e, departments d;
쿼리 | 예시 |
select * from table a, table b where 조건; |
select * from employees e, departments d where e.department_id = d.department_id; |
(1.1) equi join의 제약
- 등가 조인은 조건에 부합하지 않는 데이터 행은 조회할 수 없다는 제약이 존재한다.
- 예를 들어 위의 쿼리문에서 department_id가 없는 데이터는 검색되지 않는다.
- 이 값이 없는 상태를 null이라고 부르는데 이 경우에는 Outer Join을 사용하여 조회할 수 있다.
(2) outer join
- 등가조인의 제약을 피하기위한 용도의 null값인 데이터도 조회할 수 있도록 하는 비등가 조인
- 키 값(조건)이 일치하지 않아도 데이터를 뽑아낸다.
- equi join이 양측의 교집합을 조회한다면, outer join은 원하는 측의 null값을 포함한 데이터를 조회한다.
쿼리 | 예시 |
select * from table a, table b, table c where a.column = b. column and b.column = c. column; |
select e.last_name, d.department_id, d.department_name, l.city from employees e, departments d, locations l where e.department_id = d.department_id(+) and d.location_id = l.location_id(+); |
[참고] (+)가 없는 쪽의 데이터는 null 여부 상관없이 조회하며, (+)가 양쪽에 있으면 오류가 난다.
(3) self join
- 하나의 테이블로 조인을 걸어야하는 경우 사용한다.
- 아래의 쿼리문은 self join을 통해서 직원과 관리자 관계를 나타내는 쿼리문이다.
쿼리 | 예시 |
select * from table a, table a where a.column = a.column; |
select m.employee_id as m_employee_id, m.last_name as m_last_name, w.employee_id as w_employee_id, w.last_name as w_last_name from employees m, employees w where m.manager_id = w.employee_id; |
(4) non equi join
- 키 값에서 = 가 아닌 다른 연산자를 이용해서 조인할 때 사용한다.
- between이 보편적으로 사용된다.
쿼리 | 예시 |
select * from table a, table b where 범위 조건; |
select e.employee_id, e.salary, j.grade_level from employees e, job_grades j where e.salary between j.lowest_sal and j.highest_sal; |
# ANSI 표준 방식
- American National Standards Institue
- 여러 dbms에서 같은 형식의 조인문을 사용하도록 미국표준협회에서 지정한 방식
- 기존의 키 값이 연산자가 아닌 on절로 처리되도록 변경되었다.
(1) equi join
쿼리 | 예시 |
select * from table a join table b on 조건; |
select * from employees e join departments d on e.department_id = d.department_id; |
(2) natural join
- 양측에 같은 컬럼이 존재한다는 가정하에 where절이 없어도 동일한 컬럼을 찾아서 조인을 수행한다.
- 동일한 컬럼이 다수인 경우, 모든 컬럼이 정보가 조인되는 카다시안 곱이 발생할 수 있다.
쿼리 | 예시 |
select * from table a natural join table b; |
select department_name, city from departments natural join locations; |
(3) join using
- 내츄럴 조인에서 키 값이 되는 컬럼을 따로 지정해주는 방식
- 문법 상 별칭을 사용할 수 없다.
쿼리 | 예시 |
select * from table a join table b using(기준이 되는 컬럼); |
select employee_id, department_name from employees e join departments d using(department_id); |
(4) outer join
- (+)와 다르게 ANSI 방식에서는 원하는 측에따라서 left, right를 사용해야한다.
- left, right, full로 구분한다.
종류
|
설명
|
|
left outer join
|
키값이 일치되는 데이터 뿌리고 왼쪽 데이터 출력
|
|
right outer join
|
키값이 일치되는 데이터 뿌리고 오른쪽 데이터 출력
|
|
full outer join
|
양측의 모든 데이터를 출력
|
쿼리 | 예시 |
select * from table a left outer join table b on 조건; |
select * from employees e left outer join departments d on e.department_id = d.department_id |
# 조인의 속도
(1) outer join의 위치
- 아우터 조인이 이너 조인 사이에 존재하는 경우 속도의 문제가 발생한다.
- 일반적으로는 아우터 조인은 이너 조인 작업이 완료된 뒤 가장 마지막에 나오는 것이 좋다.
(2) on절의 컬럼 위치
- on절은 메인 테이블이 먼저 나오는 것이 속도 측면에서 좋다.
잘못된 예시 | 옳은 예시 |
select a.col1, b.col2, c.col3, d.col4 from a inner join b on a.col = b.col left outer join c on b.col = c.col inner join d on a.col = d.col; |
select a.col1, b.col2, c.col3, d.col4 from a inner join b on a.col = b.col inner join d on a.col = d.col left outer join c on b.col = c.col; |
# 조인의 순서
- on절의 내용은 where절보다 먼저 처리된다.
- on과 where의 차이는 등가 조인에서는 상관이 없으나 비등가 조인에서는 Join의 범위가 달라진다는 차이가 있다.
from - on - join - where
(1) where
- Join이 먼저 동작하여 null값까지 먼저 가져온 뒤, where절이 동작하여 행을 제어한다.
- Join의 처리 후 where절까지 두번의 동작이 있으므로 성능적으로는 (2)보다 떨어진다.
select
*
from departments d
left outer join employees e on d.department_id = e.department_id
where e.salary >= 10000;
(2) On
- On 문장만 동작하여 Salary가 1000 이상인, null값을 포함한 목록을 가져온다.
select
*
from departments d left outer join employees e
on d.department_id = e.department_id and e.salary >= 10000;
[결론]
(1) where 문장은 outer join으로 가져온 뒤 where조건으로 조건에 들어맞는 행만 가져오므로 사실상 equi join과 같다.
(2) 성능적인 측면에서는 on조건 한번으로 목록을 가져오는 방법이 더 뛰어나다.