DAY08. SQL JOIN (Join์ ์ข ๋ฅ, Cross Join, Inner Join, Outer Join)
JOIN์ ์ข ๋ฅ (๋ฌผ๋ฆฌ์ ์กฐ์ธ)
Nested Loops Join
Sort Merge Join
Hash Match Join
FOREIGN KEY์กฐ์ธ
ํ
์ด๋ธ์ ์๋ ๊ฐ์ ๋ค๋ฅธ ํ
์ด๋ธ์ ์ฐธ์กฐ(์ฐ๊ฒฐ)ํ์ฌ ์ถ๋ ฅ
<์กฐ์ธ ์ ์ฐจ>
1. ๊ธฐ๋ณธํค๊ฐ ํฌํจ๋ ํ
์ด๋ธ(master table) ์์ฑ
2. ๊ธฐ๋ณธํค๊ฐ ํฌํจ๋ ํ
์ด๋ธ์ ๋ ์ฝ๋ ์ฝ์
3. ์ธ๋ํค๊ฐ ํฌํจ๋ ํ
์ด๋ธ(transaction table) = ๊ฑฐ๋ํ
์ด๋ธ ์์ฑ
4. ์ธ๋ํค๊ฐ ํฌํจ๋ ํ
์ด๋ธ์ ๋ ์ฝ๋ ์ฝ์
* ์กฐ์ธ ํ
์ด๋ธ ์ญ์ : ์ญ์. ์ธ๋ํค ํฌํจ ํ
์ด๋ธ ์ญ์ ->๊ธฐ๋ณธํค ํฌํจ ํ
์ด๋ธ ์ญ์
* ๊ฐ์ ํ
์ด๋ธ ์ญ์ : DROP TABLE ํ
์ด๋ธ๋ช
CASCADE CONSTRAINT;
1. ๊ธฐ๋ณธํค๊ฐ ํฌํจ๋ ํ
์ด๋ธ ์์ฑ
CREATE TABLE goods(
gcode NUMBER(2) PRIMARY KEY, -- ์ฃผํค. ์ํ์ฝ๋
gname VARCHAR(20), -- ์ํ๋ช
price INT -- ๋จ๊ฐ
);
2. ๊ธฐ๋ณธํค๊ฐ ํฌํจ๋ ํ
์ด๋ธ์ ๋ ์ฝ๋ ์ฝ์
INSERT INTO goods VALUES (10, '์ฌ๊ณผ', 5000);
INSERT INTO goods VALUES (20, '๋ณต์ญ์', 8000);
INSERT INTO goods VALUES (30, 'ํฌ๋', 3000);
3. ์ธ๋ํค๊ฐ ํฌํจ๋ ํ
์ด๋ธ ์์ฑ
CREATE TABLE sale(
gcode NUMBER(2) PRIMARY KEY,
sale_date DATE,
su NUMBER(3),
FOREIGN KEY(gcode) REFERENCES goods(gcode)-- ์ธ๋ํค
);
4. ์ธ๋ํค๊ฐ ํฌํจ๋ ํ
์ด๋ธ์ ๋ ์ฝ๋ ์ฝ์
INSERT INTO sale VALUES(10, sysdate, 5);
INSERT INTO sale VALUES(20, sysdate, 10);
INSERT INTO sale VALUES(30, sysdate, 8);
INSERT INTO sale VALUES(40, sysdate, 8); -- error. WHY? ์ฐธ์กฐ ๋ฌด๊ฒฐ์ฑ ์ ์ฝ์กฐ๊ฑด ์๋ฐฐ. ๋ง์คํฐ ํ
์ด๋ธ์ ์๋ gcode ์ถ๊ฐ ๋ถ๊ฐ๋ฅ
DB๋ฐ์
COMMIT;
๋ฌผ๋ฆฌ์ join์ ๋ณ์นญ ์ง์
SELECT g.gcode, g.gname, s.su, g.price -- (์ถ์ฒ(๋ณ์นญ).์นผ๋ผ๋ช
)
FROM goods g, sale s -- ํ ์นธ ์ฌ์ด๋๊ธฐ๋ก ํ
์ด๋ธ ๋ณ์นญ ์ง์ ๊ฐ๋ฅ. SELECT, WHERE์ ์์๋ ASํ์
WHERE g.gcode = s.gcode -- ์กฐ์ธ์กฐ๊ฑด(ํ์). ๋ ํ
์ด๋ธ์ ์ฐ๊ฒฐํ ๋, ์ด๋ค ์นผ๋ผ์ ๊ฐ์ง๊ณ ์ฐ๊ฒฐํ ๊ฒ์ธ๊ฐ
AND s.su >= 8;-- ์ผ๋ฐ์กฐ๊ฑด
JOIN์ ์ข ๋ฅ (๋ ผ๋ฆฌ์ ์กฐ์ธ)
Cross Join ์กฐ๊ฑด ์์ด ํ ์ด๋ธ ์ฐ๊ฒฐ
Inner Join ์กฐ์ธ ์กฐ๊ฑด์ ๋ง์กฑํ๋ ํ๋ง ๋์์ผ๋ก ์กฐ์ธ
Outer Join ์กฐ์ธ ์กฐ๊ฑด์ ๋ง์กฑํ์ง ์๋ ํ๋ ํฌํจํ๋ ์กฐ์ธ
Self Join
Cross Join
= ์นดํฐ์ ์กฐ์ธ
ํน๋ณํ ํค์๋ ์์ด SELECT ๋ฌธ์ FROM ์ ์ ํ ์ด๋ธ์ ์ฝค๋ง๋ก ์ฐ๊ฒฐ
SELECT * FROM EMP, DEPT;
* Cross Join์ ๊ฒฐ๊ณผ๋ ์๋ฌด๋ฐ ์๋ฏธ๋ฅผ ๊ฐ์ง ๋ชปํ๋ค.
*์กฐ์ธ ๊ฒฐ๊ณผ๊ฐ ์๋ฏธ๋ฅผ ๊ฐ์ผ๋ ค๋ฉด ์กฐ์ธํ ๋ ์กฐ๊ฑด์ ์ง์ ํด์ผ ํ๋ค.
Inner Join
Inner JOIN์ ๊ฐ์ฅ ๋ง์ด ์ฌ์ฉํ๋ ์กฐ์ธ ๋ฐฉ๋ฒ
์กฐ์ธ ๋์์ด ๋๋ ๋ ํ ์ด๋ธ์์ ๊ณตํต์ ์ผ๋ก ์กด์ฌํ๋ ์ปฌ๋ผ์ ๊ฐ์ด ์ผ์น๋๋ ํ์ ์ฐ๊ฒฐํ์ฌ ๊ฒฐ๊ณผ๋ฅผ ์์ฑ
์กฐ๊ฑด์ด ์ง์ ๋์ง ์์ผ๋ฉด cross join๊ณผ ๊ฐ์ ์ฐ์ฐ์ ์ํ
SELECT *
ANSI Inner Join -- ํ์คFROM emp, dept
WHERE emp.deptno=dept.deptno; -- (ํ
์ด๋ธ ์ถ์ฒ.๊ณตํต์นผ๋ผ)
*๋ ์นผ๋ผ์ ์๋ฃ๊ฐ ์๋ ๊ฒฝ์ฐ์๋ง ์กฐ์ธ -> 14๊ฐ์ ํ, 11๊ฐ์ ์ด
SELECT *
FROM emp, dept
WHERE emp.deptno=dept.deptno -- ์กฐ์ธ์กฐ๊ฑด
AND ename='SCOTT'; -- ์ผ๋ฐ์กฐ๊ฑด
์นผ๋ผ๋ช
์ ๋ชจํธ์ฑ ํด๊ฒฐ : ์นผ๋ผ๋ช
ํ๊ธฐ, ๋ณ์นญ ํ๊ธฐ
SELECT ename, dname, deptno -- ์ ์ผ ์นผ๋ผ์ ์ถ์ฒํ๊ธฐ ์๋ต ๊ฐ๋ฅ
FROM emp, dept
WHERE emp.deptno = dept.deptno -- error. WHY? SELECT์ ๊ณผ WHERE์ ์ ์นผ๋ผ๋ช
ํ๊ธฐ๊ฐ ์์
AND ename='SCOTT';
SELECT emp.ename, dept.dname, emp.deptno -- ์นผ๋ผ๋ช
ํ๊ธฐ
FROM emp, dept
WHERE emp.deptno = dept.deptno
AND ename='SCOTT';
SELECT e.ename, d.dname, e.deptno
FROM emp e, dept d -- ๋ณ์นญ ์ค์
WHERE e.deptno=d.deptno
AND ename='SCOTT';
SELECT ename, dname, emp.deptno -- deptno๋ ์ถ์ฒ ๋ฐํ์ผํจ
FROM emp INNER JOIN dept
ON emp.deptno = dept.deptno -- ์กฐ์ธ ์กฐ๊ฑด
WHERE ename = 'SCOTT'; -- ์ผ๋ฐ ์กฐ๊ฑด
[์์ ] ๋ด์์์ ๊ทผ๋ฌดํ๋ ์ฌ์์ ์ด๋ฆ๊ณผ ๊ธ์ฌ๋ฅผ ์ถ๋ ฅํ์์ค.(EMP, DEPT ์ด์ฉ)
sub query๋ก๋ ํ์ด ๊ฐ๋ฅ
SELECT ename, sal
FROM emp, dept
WHERE emp.deptno = dept.deptno
AND loc = 'NEW YORK';
[์์ ] ACCOUNTING ๋ถ์ ์์ ์ฌ์์ ์ด๋ฆ, ์
์ฌ์ผ, ๊ทผ๋ฌด์ง์ญ์ ์ถ๋ ฅํ์์ค.
SELECT ename, hiredate, loc, dname
FROM emp, dept
WHERE emp.deptno = dept.deptno
AND dname = 'ACCOUNTING';
[์์ ] ์ง๊ธ์ด MANAGER์ธ ์ฌ์์ ์ด๋ฆ, ๋ถ์๋ช
์ ์ถ๋ ฅํ์์ค
SELECT ename, dname
FROM emp, dept
WHERE emp.deptno = dept.deptno
AND job = 'MANAGER';
[์์ ] ํ์ํ
์ด๋ธ(student)๊ณผ ๊ต์ํ
์ด๋ธ(professor) ์กฐ์ธํ๊ธฐ
๊ต์๋ฒํธ(profno) ์นผ๋ผ์ ๊ธฐ์ค ์กฐ์ธํ์ฌ ํ์๋ช
, ํ๊ณผ, ๊ต์๋ช
, ๊ต์๋ฒํธ ์นผ๋ผ์ ์กฐํํ์์ค.
SELECT *
FROM student, professor
WHERE student.profno = professor.profno; -- 15๊ฐ ๊ฐ ๋์ถ : ๊ต์๋ฒํธ๊ฐ ์๋ ํ์์ด ์์
SELECT s.name ํ์๋ช
, s.deptno1 ํ๊ณผ, p.name ๊ต์๋ช
, p.profno ๊ต์๋ฒํธ
FROM student s, professor p
WHERE s.profno = p.profno;
[์์ ] ์ ๋ฌธ์ ์ ๊ฒฐ๊ณผ์์ 101 ํ๊ณผ๋ง ๊ฒ์๋๋๋ก ํ์์ค.
SELECT s.name ํ์๋ช
, s.deptno1 ํ๊ณผ, p.name ๊ต์๋ช
, p.profno ๊ต์๋ฒํธ
FROM student s, professor p
WHERE s.profno = p.profno
AND s.deptno1 = 101;
Self join
SELECT e1.*, e2.*
FROM emp e1, emp e2; -- ์ถ๋ ฅ๊ฐ ๋ชจ์ : 196ํ 16์ด (ํ๋ผ๋ฆฌ ๊ณฑํด์ง๊ณ , ์ด์ ๋ํด์ง). ์๋ฃ ๋ถ์กฑํ ์นผ๋ผ ๊ฐ์ NULL
Outer Join : ์๋ฃ๊ฐ ๋ถ์กฑํ ์นผ๋ผ์ ์ถ๊ฐ, ๊ธฐ์ค ํ ์ด๋ธ ์์
= Left outer join (์ผ์ชฝ ํ ์ด๋ธ์ ๊ธฐ์ค์ผ๋ก ์กฐ์ธ)
SELECT e1.ename ์ฌ์๋ช
, e2.ename ์์ฌ๋ช
FROM emp e1, emp e2
WHERE e1.mgr = e2.empno (+); -- ์์ฌ๊ฐ ์๋ ๋ํ๊น์ง ๋ชจ๋ ์ถ๋ ฅ
[์์ ] EMP ํ
์ด๋ธ๊ณผ DEPT ํ
์ด๋ธ์ ์กฐ์ธํ์ฌ ์ฌ์์ด๋ฆ๊ณผ ๋ถ์๋ฒํธ์ ๋ถ์๋ช
์ ์ถ๋ ฅํ์์ค.
DEPT ํ
์ด๋ธ์ 40๋ฒ ๋ถ์์ ์กฐ์ธํ EMP ํ
์ด๋ธ์ ๋ถ์๋ฒํธ๊ฐ ์์ง๋ง, 40๋ฒ ๋ถ์์ ์ด๋ฆ๋ ์ถ๋ ฅํ์์ค
SELECT ename, d1.deptno, dname
FROM emp e1, dept d1
WHERE d1.deptno = e1.deptno (+); -- ์๋ฃ๋ฅผ ๋ชจ๋ ๊ฐ์ง๊ณ ์๋ ํ
์ด๋ธ : ๊ธฐ์คํ
์ด๋ธ
ANSI Outer Join (LEFT OUTER JOIN)
SELECT *
FROM DEPT01 LEFT OUTER JOIN DEPT02
ON DEPT01.DEPTNO = DEPT02.DEPTNO;
[์์ ] ANSI Outer Join์ ์ด์ฉํด ์ง๋๊ต์๊ฐ ์๋ ํ์ ์ถ๋ ฅ
SELECT s.name ํ์๋ช
, p.name ๊ต์๋ช
FROM student s LEFT OUTER JOIN professor p
USING(profno);
์๋ฌธ์ SQL๋ฌธ์ผ๋ก ํํํ๊ธฐ
SELECT s.name ํ์๋ช
, p.name ๊ต์๋ช
FROM student s, professor p
WHERE s.profno = p.profno (+);
[์์ ] Right Outer Join์ ์ด์ฉํ์ฌ ์ง๋๊ต์๊ฐ ์๋ ํ์ ์ถ๋ ฅ
SELECT s.name ํ์๋ช
, p.name ๊ต์๋ช
FROM student s, professor p
WHERE s.profno(+) = p.profno;
[์์ ] ANSI Right Outer Join์ ์ด์ฉํด ์ง๋๊ต์๊ฐ ์๋ ํ์ ์ถ๋ ฅ (ANSI Right Outer Join)
SELECT s.name ํ์๋ช
, p.name ๊ต์๋ช
FROM student s RIGHT OUTER JOIN professor p
USING(profno); -- USING ์ ์์ ์ฐ์ธ ์กฐ๊ฑด์ ์ถ์ฒํ๊ธฐ ์์ด SELECT์ ์์ ์ฐ์ผ ์ ์์
์ฐ์ต๋ฌธ์
๋ฌธ1) ๊ณ ๊ฐ(user_data)ํ
์ด๋ธ๊ณผ ์ง๋ถ(pay_data)ํ
์ด๋ธ์ inner joinํ์ฌ ๋ค์๊ณผ ๊ฐ์ด ์ถ๋ ฅํ์์ค.
์กฐ๊ฑด1) ๊ณ ๊ฐID(user_id), ์ฑ๋ณ(gender), ์ฐ๋ น(age), ์ง์
์ ํ(job), ์ํ์ ํ(product_type), ์ง๋ถ๋ฐฉ๋ฒ(pay_method), ๊ตฌ๋งค๊ธ์ก(price) ์นผ๋ผ ์ถ๋ ฅ
์กฐ๊ฑด2) ๊ณ ๊ฐID ์ค๋ฆ์ฐจ์ ์ ๋ ฌ
SELECT u.*, p.product_type, p.pay_method, p.price
FROM USER_DATA u, PAY_DATA p
WHERE u.user_id = p.user_id
ORDER BY u.user_id;
-- [ํด์ค] ์ ์ฒด ๊ณ ๊ฐ 10์ค์์ ์ํ์ ๊ตฌ๋งคํ ๊ณ ๊ฐ ๋ ์ฝ๋ ์ถ๋ ฅ
๋ฌธ2) ๋ฌธ1)์ ๊ฒฐ๊ณผ์์ ์ฑ๋ณ์ด '์ฌ์'์ด๊ฑฐ๋ ์ง๋ถ๋ฐฉ๋ฒ์ด '1.ํ๊ธ'์ธ ๊ฒฝ์ฐ๋ง ์ถ๋ ฅํ์์ค.
๋จ : gender=1, ์ฌ : gender=2
SELECT u.*, p.product_type, p.pay_method, p.price
FROM USER_DATA u, PAY_DATA p
WHERE u.user_id = p.user_id AND (u.gender=2 OR p.pay_method = '1.ํ๊ธ')
ORDER BY u.user_id;
-- [ํด์ค] ์ผ๋ฐ ์กฐ๊ฑด ์ถ๊ฐ : ์ํ ๊ตฌ๋งค ๊ณ ๊ฐ ์ค์์ ํน์ ๊ณ ๊ฐ ์กฐํ
๋ฌธ3) ๊ณ ๊ฐ(user_data)ํ
์ด๋ธ๊ณผ ์ง๋ถ(pay_data)ํ
์ด๋ธ์ left outer joinํ์ฌ ๋ค์๊ณผ ๊ฐ์ด ์ถ๋ ฅํ์์ค.
์กฐ๊ฑด) ๊ณ ๊ฐID, ์ฑ๋ณ, ๋์ด, ์ํ์ ํ, ์ง๋ถ๋ฐฉ๋ฒ ์นผ๋ผ ์ถ๋ ฅ
SELECT u.user_id, gender, age, p.product_type, p.pay_method
FROM USER_DATA u, PAY_DATA p
WHERE u.user_id = p.user_id(+);
-- [ํด์ค] ์ ์ฒด ๊ณ ๊ฐ 10์ค์์ ์ํ์ ๊ตฌ๋งคํ์ง ์์ ๊ณ ๊ฐ๊น์ง ์ถ๋ ฅ
๋ฌธ4) ๊ณ ๊ฐ(user_data)ํ
์ด๋ธ๊ณผ ๋ฐํ(return_data)ํ
์ด๋ธ์ ์ด์ฉํ์ฌ left outer joinํ์ฌ ๋ค์๊ณผ ๊ฐ์ด ์ถ๋ ฅํ์์ค.
์กฐ๊ฑด1) ๊ณ ๊ฐID, ์ฑ๋ณ, ๋์ด, ๊ฑฐ์ฃผ์ง์ญ, ๋ฐํ์ฝ๋ ์นผ๋ผ ์ถ๋ ฅ
์กฐ๊ฑด2) ๋ฐํํ ๊ณ ๊ฐ๋ง ์ถ๋ ฅ
SELECT u.user_id, gender, age, resident, return_code
FROM USER_DATA u, RETURN_DATA r
WHERE u.user_id = r.user_id(+)
AND return_code IS NOT NULL;
-- [ํด์ค] ์ ์ฒด ๊ณ ๊ฐ ์ค์์ ์ํ์ ๋ฐํํ ๊ณ ๊ฐ๋ง ์ถ๋ ฅ
-- inner join ํํ
SELECT u.user_id, gender, age, resident, return_code
FROM USER_DATA u, RETURN_DATA r
WHERE u.user_id = r.user_id;