Back to the DataBase

MySQL Join 쿼리 / 효율적인 DB의 시작

Backcoder 2022. 7. 14. 19:14

< Join 쿼리 >

=> 테이블1에 특정 컬럼의 동일값이 반복된다.
( 변경할때도 그 동일값이 다 변경되어야 해서 낭비 )
=> 중복되고, 연관된 요소들을 따로 빼서 테이블2를 만들자

( 테이블을 어떻게 구성할지 잘 생각해야한다. )

중복되는 요소 컬럼들을 따로 빼서 테이블2를 만들면,
원래 테이블1은 간단해진다.

테이블 1과 테이블2가 칼럼 하나만 공유하고있으면
연결고리
테이블1은 테이블2 데이터를 가져다 쓸 수 있다. (vice versa)

select 테이블1 칼럼, 테이블2 칼럼 from 테이블1, 테이블2
WHERE 테이블1.공유칼럼 = 테이블2.공유칼럼 ;

select first_name, department_name from employees, departments
where employees.department_id = departments.department_id;

( 공유 칼럼 ( JOIN KEY ) 는 가져올 때, 어디 테이블 소속걸로 가져올지 표시해줘야함 - Ambiguous)
select firt_name, department_name, employee.department_id, from employees, departments
where employees.department_id = departments.department_id;

=> 길어서, 알리아스를 사용해 짧게 표현하는 방법을 많이 사용한다.

select first_name, department_name, e.department_id
from emplyees e, departments d
where e.department_id = d.department_id;


=> 근데 이렇게 where 절join 시키게되면, 다른 where 조건과 헤깔려서 보기 안좋다.

select name,department from e, d
where e.depid = d.depid
AND name like '%le%';
뭐 이렇게 AND 로 조건 주면 되기는 한다.

근데 헤깔리니까 MySQL(전용) 에서 구분하라고 문법하나 제공해준다.
( 이걸 많이 쓰니, 알아두고 사용할 줄 알아야겠다.)

select first_name, department_name, e.department_id
from employees e
INNER JOIN departments d
ON e.department_id = d.department_id
WHERE name like '%le%';

INNERJOIN => 사실 메인 테이블은 employees 인거고, 여기 안으로 조인을 시키겠다. departments 테이블을
ON => A테이블 공유칼럼 = B 테이블 공유칼럼 일때.
WHERE => 이제 조건 주고싶은거 주면 된다.

즉, 조인했다는걸 INNER JOIN 으로 명시해주고,
어떤 공유칼럼으로 JOIN 한건지 ON 으로 명시해주고,
WEHRE 은 진짜 조회조건들만 들어가면 되므로
가독성이 향상된다.


( 일반적으로 'Join 한다' 라 함은 INNER JOIN 을 말한다. 실무에서도 사용하는 Join 은 사실상 대개가 INNER JOIN. )


< 여러 테이블 Join >

이제, 테이블이 더 여러개 있다고 생각해보자.

사원테이블, 부서테이블, 지역테이블, 나라테이블

사원별로, 부서, 지역, 나라를 출력하고 싶다.
구조는 다음과 같다.

select A, B, C
from A
Inner Join B
on A.공유 = B.공유
Inner Join C
on B.공유 = C.공유
Inner Join D
on C.공유 = D.공유
where ~ ;

=> 먼저 테이블끼리 Join 할 수 있도록 공유하는 컬럼을 가지고 있어야 한다. ( 연결고리 )
=> 연결고리가 있다면, Inner Join 을 연속해서 사용해 주면 된다.
=> 이 때, Inner join 다음 Inner join 을 하면
자동으로 center 테이블( 직전에 Inner join을 한 테이블 ) 에 join 을 시도한다.

( A 가 B 랑 inner join 을 했고, 다음에 inner join C 를 한다면,
A - B - C
바로 직전에 inner join 한 B 가 말 그대로 가운데 있기 때문에, center 테이블이 된다.
C 는 자동으로 center table인 B 와 inner join 을 하게 된다. )

=> 이렇게 하면
C 입장에서는 B 와 조인이 가능한지만 확인하면, A 는 B와는 조인이 되어있기 때문에,
자동으로 C 도 A 와 조인이 되는 것.


- Inner Join 할때 주의사항
=> 양 테이블에 모두 존재하고, join 조건에 일치하는 데이터만 합침
( join 조건 : 공유칼럼1 = 공유칼럼2 )
그런데, 공유하는 Join Columnnull 값이 있다면
그 데이터는 가져오지 못한다.
( 사실, 그래서 공유 join key 값은 보통 not null로 설정 )

이럴 때, 우회해서 null 값도 가져올 수 있는 Join 방법이 바로

=> Outer Join : 조건 일치하지 않아도 데이터만 합침!

< Left Outer Join > ( Left가 기본 )

select A,B
from A
left outer join B
on A. 공유 = B. 공유;

( 현재 테이블 모습 : A - B )
: Left 에있는 테이블A 한테 조인할게 outer 방식으로 ( 주인 : A )
즉, null 인것도 가져올게

=> 조인하는 공유칼럼 자체에 null 값이 있더라도, 그것도 가져와줌



< Right Outer Join > ( 주객전도 )

select A,B
from  A
Right Outer Join B
on A. 공유 = B. 공유;

( 현재 테이블 모습 : A - B )
: Right 에 있는 테이블 B 한테 조인할게 outer방식으로 ( 주인 : B )
=> 즉 이제부턴 B, 내 기준이야!
( A 가 주인일 때는, A 에 레코드가 있는 것을 기준으로 B 를 조인 시켰다.
B에 이런저런 데이터가 있었는데, 그걸 사용하는 A 가 없었으면
그것들은 조회되지 못했다.
예를들어, A의 사원을 기준으로 조회가 되는데
B에 봉사 부서, 잡종 부서 등 요상한 부서들이 많이 있는데, A의 사원중에 그런 부서에 든 사람이 없다면,
조회할 때, 이런 요상한 부서들은 조회자체가 안됬다. )

=> 근데 이제 B가 주인이 되서 조회를 하기 때문에,
B의 잡종부서들도 다 조회가 된다. B가 기준이니까.
( A에 잡종부서 들어간 사원이 없는건 니 사정이고, null 로 표시는 해줄게 )
< 사원 > < 부서 >
null 봉사부서
null 잡종부서


=> Right 가 이런 의미를 가지므로, 만약

select A,B
from B
Right Outer Join A
on A. 공유 = B. 공유;

(현재 테이블 모습 : B - A )
기본 테이블을 부서(B)로 잡아놓고
right outer join 을 하면 오른쪽에 있는 A 테이블이 기준인 조인이 되므로
사원(A)가 기준인 join,
즉 처음에 사원(A)에 Left outer join 으로 부서(B) 조인 시키는거랑 똑같은 결과가 나오겠다.


( Full outer join <= 다른 DB 에선 가능 / Mysql 은 불가능 )


< Self Join > => 테이블 자기자신과 Join ( 복사해서 사용 )

상황 : A 테이블에서 매니저id 를 조회한 값으로
=> 그걸 다시 A테이블의 사원id로 집어넣어서 조회하면 그 매니저를 찾을 수 있다.

( june 의 매니저를 찾기 위해, 먼저 june 의 매니저 아이디를 찾아보자 )

select manager_id
from employees
where first_name = 'june' ;
=> 매니저 아이디가 122였다. 누군지 조회해보자.

select first_name from employees
where employee_id = 122;
=> Tom // 매니저는 Tom 이었다.

=> 이 쿼리 두개를 한방에 해보자 ( SELF JOIN )
( 처음에 매니저아이디 찾고 => 이거 이용해서 매니저를 찾기 )

select A.first_name, B.first_name
from employees A
Inner Join employees B
ON A.manager_id = B.employee_id;
=> 첫 테이블에서의 매니저아이디가 조인한 테이블의 사번과 같을 때 그 사람이 매니저
( 구별하기 위해 알리아스 필수 )
=> june - tom
( 사원이름 - 매니저이름이 조회된다. )




< cross join >
cross join 은 잘못된 join (의미없는 join) 을 말한다.

예를들어, JOIN 할때, ON 조건 없이 실행하면
JOIN 되는 순서도 멋대로고, 의미도 없는 조인이다.

이거 하지 않도록 주의해야한다.
( 실무에서 '그거 크로스 조인된거 아니야? ' 뭐 이런 식으로 사용되지 않을까 )



=> 끝으로, JOIN 을 할때는 본래 공유컬럼에 명시적으로 FOREIGN KEY 를 걸어두고 사용하는게 일반적이다.
걸어두지 않아도 JOIN이 되긴하지만 '참조 무결성의 원칙' 을 이유로 사실 상 거의 걸어두고 사용하기 때문에,
JOIN 을 하고자 하면 FOREIGN KEY 의 사용법도 알아두어야 한다.
( 따로 정리 )




이렇게, 처음 테이블을 생성할 때는
먼저 데이터들의 연관관계를 파악하고
테이블은 몇 개를 만들고, 어떤걸 JOIN 시켜서 사용할지
최대한 효율적으로 테이블들을 설계해서 DB를 구축하는것이
매우 중요한 역량이라 생각된다.