[SQL Fundamentals] 02. ์กฐ์ธ(Join) - Outer ์กฐ์ธ, Non Equi ์กฐ์ธ, Cross ์กฐ์ธ
by Hi.Claire๐ฅ๏ธ ๋ฐ์ดํฐ ๋ถ์ SQL Fundamentals (๊ถ์ฒ ๋ฏผ, ์ธํ๋ฐ)
์น์ 2. ์กฐ์ธ(Join) - Outer ์กฐ์ธ, Non Equi ์กฐ์ธ, Cross ์กฐ์ธ
2-1. Inner ์กฐ์ธ, Left/Right Outer ์กฐ์ธ, Full Outer ์กฐ์ธ์ ์ดํด
Inner Join
from A
join B on A.key = B.key
inner๋ฅผ ์๋ตํ๊ณ (inner) join์ผ๋ก๋ ์ฌ์ฉํ ์ ์๋ค.
join์ ๋ฐฉํฅ์ LEFT -> RIGHT์ด๋ LEFT <- RIGHT์ด๋ ์๊ด์๋ค.
์์ ์์์์ LEFT ํ ์ด๋ธ๊ณผ RIGHT ํ ์ด๋ธ์ ๊ด๊ณ๊ฐ M:1์ด๋ฏ๋ก ์กฐ์ธ ๊ฒฐ๊ณผ ๋ฐ์ดํฐ ์งํฉ ๋ ๋ฒจ์ LEFT ํ ์ด๋ธ์ ์งํฉ ๋ ๋ฒจ์ ๋ฐ๋ฅด๊ฒ ๋๋ฉฐ ๊ฒฐ๊ณผ์ ์ผ๋ก๋ ๋ ํ ์ด๋ธ์ ํค๊ฐ์ด ์ผ์นํ๋ ๋ฐ์ดํฐ๋ง ๊ฑธ๋ฌ์ ธ์ ๋์จ๋ค.
์น์ 1์ ์ค์ต ์์ ๊ฐ ๋ชจ๋ inner join์ ์์์ด๋ฏ๋ก ์ด๋ฒ ๊ธ์์๋ inner join์ ์ค์ต ์์ ๋ ์๋ตํ๋ค.
(์ฐธ๊ณ ) inner join ์ค์ต ์์
https://moominie.tistory.com/33
[SQL Fundamentals] 01. ์กฐ์ธ(Join) - ์กฐ์ธ ๊ธฐ๋ฐ ๋ฉ์ปค๋์ฆ
๐ฅ๏ธ ๋ฐ์ดํฐ ๋ถ์ SQL Fundamentals (๊ถ์ฒ ๋ฏผ, ์ธํ๋ฐ) ์น์ 1. ์กฐ์ธ(Join) - ์กฐ์ธ ๊ธฐ๋ฐ ๋ฉ์ปค๋์ฆ 1-1. ์กฐ์ธ ๊ฐ์ ์กฐ์ธ(Join) RDBMS(Relational DBMS, ๊ด๊ณํ DBMS)์์ ๊ฐ์ฅ ๊ธฐ๋ณธ์ด์ ์ค์ํ ๊ธฐ๋ฅ ๋ ๊ฐ ์ด์์ ํ ์ด
moominie.tistory.com
Left Outer Join
from A
left join B on A.key = B.key
outer๋ฅผ ์๋ตํ๊ณ left (outer) join์ผ๋ก๋ ์ฌ์ฉํ ์ ์๋ค.
join์ ๋ฐฉํฅ์ LEFT -> RIGHT๋ก ์ ํด์ง๋ฉฐ, ์ด๋ LEFT ํ ์ด๋ธ์ด Outer ํ ์ด๋ธ์ด ๋๊ณ , RIGHT ํ ์ด๋ธ์ด Inner ํ ์ด๋ธ์ด ๋๋ค.
์์ ์์์์๋ LEFT ํ ์ด๋ธ๊ณผ RIGHT ํ ์ด๋ธ์ ๊ด๊ณ๊ฐ M:1์ด๋ฏ๋ก ์กฐ์ธ ๊ฒฐ๊ณผ ์งํฉ์ LEFT (Outer) ํ ์ด๋ธ์ ๋ฐ์ดํฐ ์งํฉ ๋ ๋ฒจ์ ๋ฐ๋ผ๊ฐ๋ฉด์ RIGHT ํ ์ด๋ธ์ ๋ฐ์ดํฐ๊ฐ ์กด์ฌํ์ง ์๋ LEFT ํ ์ด๋ธ์ ๋ฐ์ดํฐ๋ค๋ ๋ณด์กด๋๋ค.
Right Outer Join
from A
right join B on A.key = B.key
Left Outer Join์ ๋ฐ๋ ๊ฐ๋ ์ด๋ค.
outer๋ฅผ ์๋ตํ๊ณ right (outer) join์ผ๋ก๋ ์ฌ์ฉํ ์ ์๋ค.
join์ ๋ฐฉํฅ์ LEFT <- RIGHT๋ก ์ ํด์ง๋ฉฐ, ์ด๋ RIGHT ํ ์ด๋ธ์ด Outer ํ ์ด๋ธ์ด ๋๊ณ , LEFT ํ ์ด๋ธ์ด Inner ํ ์ด๋ธ์ด ๋๋ค.
์์ ์์์์ LEFT ํ ์ด๋ธ๊ณผ RIGHT ํ ์ด๋ธ์ ๊ด๊ณ๊ฐ M:1์ด๋ฏ๋ก ์กฐ์ธ ๊ฒฐ๊ณผ ์งํฉ์ LEFT (Inner) ํ ์ด๋ธ์ ๋ฐ์ดํฐ ์งํฉ ๋ ๋ฒจ์ ๋ฐ๋ผ๊ฐ๋ฉด์ LEFT ํ ์ด๋ธ์ ๋ฐ์ดํฐ๊ฐ ์กด์ฌํ์ง ์๋ RIGHT ํ ์ด๋ธ์ ๋ฐ์ดํฐ๋ ๋ณด์กด๋๋ค.
(์ฐธ๊ณ )
right join์ LEFT ํ ์ด๋ธ๊ณผ RIGHT ํ ์ด๋ธ์ ์์น๋ง ๋ฐ๊พธ๋ฉด left join๊ณผ ๊ฒฐ๊ณผ๊ฐ ๋๊ฐ๋ค.
์๋ ๋ join์ ๊ฒฐ๊ณผ๋ ๊ฐ๋ค.
from A
right join B on A.key = B.key
from B
left join A on B.key = A.key
Full Outer Join
from A
full join B on A.key = B.key
Online๋ณด๋ค๋ Batch์์ ์ฌ์ฉํ๋ ๊ฒฝ์ฐ๊ฐ ๋ง๋ค.
outer๋ฅผ ์๋ตํ๊ณ full (outer) join์ผ๋ก๋ ์ฌ์ฉํ ์ ์๋ค.
์์ ์์์์ LEFT ํ ์ด๋ธ๊ณผ RIGHT ํ ์ด๋ธ์ ๊ด๊ณ๊ฐ M:1์ด๋ฏ๋ก ์กฐ์ธ ๊ฒฐ๊ณผ ๋ฐ์ดํฐ ์งํฉ ๋ ๋ฒจ์ LEFT ํ ์ด๋ธ์ ๋ฐ์ดํฐ ์งํฉ ๋ ๋ฒจ์ ๋ฐ๋ผ๊ฐ๋ฉด์ ์๋ก์ ํ ์ด๋ธ์ ๋ฐ์ดํฐ๊ฐ ์กด์ฌํ์ง ์๋ ๋ฐ์ดํฐ๋ค๊น์ง ๋ชจ๋ ๋ณด์กด๋๋ค.
2-2. Outer ์กฐ์ธ ์ค์ต
์ค์ต์์
1. ์ฃผ๋ฌธ์ด ๋จ ํ๋ฒ๋ ์๋ ๊ณ ๊ฐ ์ ๋ณด ๊ตฌํ๊ธฐ
1
2
3
4
|
select c.*
from customers c
left join orders o on c.customer_id = o.customer_id
where o.order_id isnull;
|
๋จ ํ๋ฒ๋ ์ฃผ๋ฌธ์ ํ์ง ์์๋๋ผ๋ ๊ณ ๊ฐ ํ ์ด๋ธ์ ์ ๋ณด๋ ๋ณด์กด์ด ๋ผ์ผ ํ๋ค.
๋ฐ๋ผ์ customers ํ ์ด๋ธ์ LEFT (Outer) ํ ์ด๋ธ๋ก ํ์ฌ left join์ ํ๊ฒ ๋๋ฉด orders ํ ์ด๋ธ์ ๋ฐ์ดํฐ๊ฐ ์๋๋ผ๋ customers ํ ์ด๋ธ์ ๋ฐ์ดํฐ๊ฐ ์จ์ ํ ๋ณด์กด๋๋ค.
2. ๋ถ์์ ๋ณด์ ๋ถ์์ ์์๋ ์ง์๋ช ์ ๋ณด ๊ตฌํ๊ธฐ. ๋ถ์๊ฐ ์ง์์ ๊ฐ์ง๊ณ ์์ง ์๋๋ผ๋ ๋ถ์์ ๋ณด๋ ํ์๋์ด์ผ ํจ
1
2
3
4
|
select d.*, e.empno, e.ename
from hr.dept d
left join hr.emp e on d.deptno = e.deptno
order by d.deptno;
|
๋ถ์์ ์์๋ ์ง์์ด ์๋๋ผ๋ ๋ถ์ ํ ์ด๋ธ์ ์ ๋ณด๋ ๋ณด์กด์ด ๋ผ์ผ ํ๋ค.
๋ฐ๋ผ์ dept ํ ์ด๋ธ์ LEFT (Outer) ํ ์ด๋ธ๋ก ํ์ฌ left join์ ํ๊ฒ ๋๋ฉด emp ํ ์ด๋ธ์ ๋ฐ์ดํฐ๊ฐ ์๋๋ผ๋ dept ํ ์ด๋ธ์ ๋ฐ์ดํฐ๊ฐ ์จ์ ํ ๋ณด์กด๋๋ค.
์๋์ ๊ฐ์ด emp ํ ์ด๋ธ์ LEFT (Outer) ํ ์ด๋ธ๋ก ํ์ฌ right join์ ํ๋๋ผ๋ ๊ฒฐ๊ณผ๋ ๋์ผํ๊ฒ ๋์จ๋ค.
1
2
3
4
|
select d.*, e.empno, e.ename
from hr.emp e
right join hr.dept d on e.deptno = d.deptno
order by d.deptno;
|
3. Madrid์ ์ด๊ณ ์๋ ๊ณ ๊ฐ์ด ์ฃผ๋ฌธํ ์ฃผ๋ฌธ ์ ๋ณด๋ฅผ ๊ตฌํ ๊ฒ.
๊ณ ๊ฐ๋ช , ์ฃผ๋ฌธid, ์ฃผ๋ฌธ์ผ์, ์ฃผ๋ฌธ์ ์ ์ง์๋ช , ๋ฐฐ์ก์ ์ฒด๋ช ์ ๊ตฌํ๋, ๋ง์ผ ๊ณ ๊ฐ์ด ์ฃผ๋ฌธ์ ํ๋ฒ๋ ํ์ง ์์ ๊ฒฝ์ฐ๋ผ๋ ๊ณ ๊ฐ์ ๋ณด๋ ๋น ์ง๋ฉด ์๋จ. ์ด๊ฒฝ์ฐ ์ฃผ๋ฌธ ์ ๋ณด๊ฐ ์์ผ๋ฉด ์ฃผ๋ฌธid๋ฅผ 0์ผ๋ก ๋๋จธ์ง๋ Null๋ก ๊ตฌํ ๊ฒ.
(๋์ ์๊ฐ)
1
2
3
4
5
6
7
|
select c.contact_name as customer_name, coalesce(o.order_id,0) as order_id, o.order_date, concat(e.first_name, ' ', e.last_name) as employee_name, s.company_name as shipper_name
from customers c
left join orders o on c.customer_id = o.customer_id
join employees e on o.employee_id = e.employee_id
join shippers s on o.ship_via = s.shipper_id
where c.city = 'Madrid'
order by c.customer_id, o.order_id;
|
์ฃผ๋ฌธ ์ ๋ณด๊ฐ ์๋๋ผ๋ ๊ณ ๊ฐ์ ๋ณด๋ ๋ณด์กด์ด ๋ผ์ผ ํ๋ฏ๋ก customers ํ ์ด๋ธ์ LEFT (Outer) ํ ์ด๋ธ๋ก ํ์ฌ orders ํ ์ด๋ธ์ left join ํ๋ค.
๊ทธ๋ฐ๋ฐ orders ํ ์ด๋ธ์ employee ์ ๋ณด๋ shipper ์ ๋ณด๊ฐ employees ํ ์ด๋ธ๊ณผ shippers ํ ์ด๋ธ์ ํญ์ ์กด์ฌํ๋ฏ๋ก employees, shippers ํ ์ด๋ธ์ ๊ทธ๋ฅ inner join์ผ๋ก ๊ฑธ์ด์ฃผ์๋๋ฐ ์ด๊ฒ ์๋ชป๋ ํ๋จ์ด์๋ค.
์ฃผ๋ฌธ ์ ๋ณด๊ฐ ์๋ ๊ณ ๊ฐ์ ๊ฒฝ์ฐ orders ํ ์ด๋ธ์ ๋ชจ๋ ๋ฐ์ดํฐ๊ฐ NULL ๊ฐ์ผ๋ก ๋์จ๋ค.
์ฆ, employees ํ ์ด๋ธ๊ณผ์ join ํค ๊ฐ์ด ๋๋ employee_id๋ NULL์ด๊ธฐ ๋๋ฌธ์ inner join์ ํ ๊ฒฝ์ฐ ํด๋น ๊ณ ๊ฐ์ ๋ฐ์ดํฐ๋ ์ ์ธ๋๋ค.
shippers ํ ์ด๋ธ๋ ๋ง์ฐฌ๊ฐ์ง๋ก join ํค ๊ฐ์ด ๋๋ ship_via๊ฐ NULL์ด๊ธฐ ๋๋ฌธ์ inner join์ ํ ๊ฒฝ์ฐ ํด๋น ๊ณ ๊ฐ์ ๋ฐ์ดํฐ๊ฐ ์ ์ธ๋๋ค.
๋ฐ๋ผ์ ์ฃผ๋ฌธ ์ ๋ณด๊ฐ ์๋ ๊ณ ๊ฐ์ ๋ณด๋ ๋ณด์กด๋๊ธฐ ์ํด์๋ employees, shippers ํ ์ด๋ธ๋ ๋ชจ๋ left join์ ๊ฑธ์ด์ฃผ์ด์ผ ํ๋ค.
(์ ๋ต)
1
2
3
4
5
6
7
|
select c.contact_name as customer_name, coalesce(o.order_id,0) as order_id, o.order_date, e.first_name || ' ' || e.last_name as employee_name, s.company_name as shipper_name
from customers c
left join orders o on c.customer_id = o.customer_id
left join employees e on o.employee_id = e.employee_id
left join shippers s on o.ship_via = s.shipper_id
where c.city = 'Madrid'
order by c.customer_id, o.order_id;
|
์ฃผ๋ฌธ ์ ๋ณด๊ฐ ์๋ ๊ณ ๊ฐ์ ๋ณด๊ฐ ๋ณด์กด๋๋ฉด์ ์ํ๋ ๊ฒฐ๊ณผ๊ฐ ๋์๋ค.
COALESCE(์ธ์1, ์ธ์2)
postgreSQL, MySQL, Oracle ๊ณตํต ํจ์
์ธ์1์ ๊ฐ์ด NULL์ด ์๋๋ฉด ์ธ์1๋ก, ์ธ์1์ ๊ฐ์ด NULL์ธ ๊ฒฝ์ฐ์๋ ์ธ์2๋ก ๋์จ๋ค.
(์ฐธ๊ณ )
IFNULL(์ธ์1, ์ธ์2)
MySQL ํจ์
COALESCE์ ๋ง์ฐฌ๊ฐ์ง๋ก ์ธ์1์ ๊ฐ์ด NULL์ด ์๋๋ฉด ์ธ์1๋ก, ์ธ์1์ ๊ฐ์ด NULL์ธ ๊ฒฝ์ฐ์๋ ์ธ์2๋ก ๋์จ๋ค.
NVL(์ธ์1, ์ธ์2)
Oracle ํจ์
COALESCE์ ๋ง์ฐฌ๊ฐ์ง๋ก ์ธ์1์ ๊ฐ์ด NULL์ด ์๋๋ฉด ์ธ์1๋ก, ์ธ์1์ ๊ฐ์ด NULL์ธ ๊ฒฝ์ฐ์๋ ์ธ์2๋ก ๋์จ๋ค.
NVL(์ธ์1, ์ธ์2, ์ธ์3)
Oracle ํจ์
์ธ์1์ ๊ฐ์ด NULL์ด ์๋๋ฉด ์ธ์2๋ก, ์ธ์1์ ๊ฐ์ด NULL์ด๋ฉด ์ธ์3์ผ๋ก ๋์จ๋ค.
COALESCE(์ธ์1, ์ธ์2, ์ธ์3)
์ธ์1์ ๊ฐ์ด NULL์ด๋ฉด ์ธ์2๋ก, ์ธ์2์ ๊ฐ๋ NULL์ด๋ฉด ์ธ์3์ผ๋ก ๋์จ๋ค.
4. order_items์ ์ฃผ๋ฌธ๋ฒํธ(order_id)๊ฐ ์๋ order_id๋ฅผ ๊ฐ์ง orders ๋ฐ์ดํฐ ์ฐพ๊ธฐ
1
2
3
4
|
select *
from orders o
left join order_items oi on o.order_id = oi.order_id
where oi.order_id isnull;
|
์ค์ ์ ๋ฌด์์ ๋ถ๋ชจ ํ ์ด๋ธ์ ๋ฐ์ดํฐ๊ฐ ์๋๋ฐ ์์ ํ ์ด๋ธ์ ๋ฐ์ดํฐ๊ฐ ์๋ ๊ฒฝ์ฐ๊ฐ ์๋์ง ์ ํฉ์ฑ์ ์ฒดํฌํ๊ธฐ ์ํด ์์ ๊ฐ์ด left outer join์ ์ฐ๋ ๊ฒฝ์ฐ๊ฐ ๋ง๋ค.
2-3. Full Outer ์กฐ์ธ ์ค์ต
์ค์ต์์
1. ์์ ์ง์์ด ์๋ ๋ถ์ ์ ๋ณด๋ฅผ ๋ณด์กดํ๊ณ , ์์ ๋ถ์๊ฐ ์๋ ์ง์ ์ ๋ณด๋ ๋ณด์กดํ์ฌ ์์ชฝ ๋ชจ๋์ ์งํฉ์ด ๋๋ฝ๋์ง ์๋๋ก ๋ฐ์ดํฐ ์ถ์ถํ๊ธฐ
1
2
3
4
|
select d.deptno, d.dname, et.empno, et.ename
from dept d
full outer join emp_test et on d.deptno = et.deptno
order by d.deptno, et.empno;
|
2-4. Non Equi ์กฐ์ธ๊ณผ Cross ์กฐ์ธ์ ์ดํด
Equi Join
์กฐ์ธ ์ ์ฐ๊ฒฐํ๋ ํค ๊ฐ์ด ์๋ก ๊ฐ์ ๊ฒฝ์ฐ (์ฆ, =๋ก ์ฐ๊ฒฐํ๋ ๊ฒฝ์ฐ)
์ฌํ๊น์ง ํ๋ ์กฐ์ธ ์ค์ต ๋ชจ๋ Equi Join์ ์ํ๋ค.
Non Equi Join
๋ ํ ์ด๋ธ์ ์ฐ๊ฒฐํ ๋ ๊ผญ ์กฐ์ธ ํค ๊ฐ์ด ์ผ์นํ๋ ๊ฒฝ์ฐ๊ฐ ์๋๋๋ผ๋ ์กฐ๊ฑด์ ๋ถํฉํ๋ค๋ฉด ์ผ๋ง๋ ์ง ์ฐ๊ฒฐ์ด ๊ฐ๋ฅํ๋ค.
์ฆ, ํค ๊ฐ์ผ๋ก ์ฐ๊ฒฐ ์ =์ด ์๋ ๋ค๋ฅธ ์ฐ์ฐ์(between, >, >=, <, <=)๋ฅผ ์ฌ์ฉํ๋ ์กฐ์ธ์ ๋งํ๋ค.
(์์) Between Join
- ์ง์์ ๋ณด์ ๊ธ์ฌ๋ฑ๊ธ ์ ๋ณด ๊ฐ์ ธ์ค๊ธฐ
1
2
3
4
|
select e.empno, e.ename, e.sal, s.grade
from emp e
join salgrade s on e.sal between s.losal and s.hisal
order by e.empno;
|
Cross Join (Cartesian Product Join)
์กฐ์ธ ์ปฌ๋ผ์์ด ๋ ํ ์ด๋ธ ๊ฐ ๊ฐ๋ฅํ ๋ชจ๋ ์ฐ๊ฒฐ์ ๊ฒฐํฉํ๋ ์กฐ์ธ ๋ฐฉ์
์กฐ์ธ ๊ฒฐ๊ณผ ์งํฉ์ ๋ ํ ์ด๋ธ์ ๋ฐ์ดํฐ ๊ฑด์๋ฅผ ๊ณฑํ ๊ฒฐ๊ณผ๋งํผ ๋์จ๋ค.
๋จ, where ์กฐ๊ฑด์ผ๋ก ๊ฑธ๋ฌ์ง ๊ฒฝ์ฐ ๊ณฑ์ ๊ฒฐ๊ณผ ๋ฐ์ดํฐ ๊ฑด์์ ์ผ์นํ์ง ์์ ์๋ ์๋ค.
(์์)
1
2
3
|
select a.*, b.*
from table a
cross join table b;
|
2-5. Non Equi ์กฐ์ธ๊ณผ Cross ์กฐ์ธ ์ค์ต
์ค์ต์์
1. ์ง์ ๊ธ์ฌ์ ์ด๋ ฅ์ ๋ณด๋ฅผ ๋ํ๋ด๋ฉฐ, ํด๋น ๊ธ์ฌ๋ฅผ ๊ฐ์ก๋ ์์ ์์ ์์์ ๋ถ์๋ฒํธ๋ ํจ๊ป ๊ฐ์ ธ์ฌ๊ฒ
1
2
3
|
select *
from hr.emp_salary_hist a
join hr.emp_dept_hist b on a.empno = b.empno and a.fromdate between b.fromdate and b.todate;
|
์๋์ ๊ฐ์ด ๊ธ์ฌ ์์ ์์ ์กฐ๊ฑด์ join ์กฐ๊ฑด์ด ์๋ where์ ์ ๋์ด๋ ๊ฒฐ๊ณผ๋ ๋์ผํ๋ค.
1
2
3
4
|
select *
from hr.emp_salary_hist a
join hr.emp_dept_hist b on a.empno = b.empno
where a.fromdate between b.fromdate and b.todate;
|
(TODO) ๋ ์ฟผ๋ฆฌ์ ์ฑ๋ฅ์?
'๐พ ๋ฐ์ดํฐ๋ฒ ์ด์ค > ๋ฐ์ดํฐ ๋ถ์ SQL Fundamentals' ์นดํ ๊ณ ๋ฆฌ์ ๋ค๋ฅธ ๊ธ
๋ธ๋ก๊ทธ์ ์ ๋ณด
Claire's Study Note
Hi.Claire