๐ SQL JOIN โ ํ ์ด๋ธ์ ์ฐ๊ฒฐํ๋ ๋ฐฉ๋ฒ
JOIN์ ์ฒ์ ๋ดค์ ๋ ์ ์ด๋ ๊ฒ ์ข
๋ฅ๊ฐ ๋ง๋ ์ถ์์ต๋๋ค.
๋ง์ ์ฐ๋ค ๋ณด๋ฉด ๊ฒฐ๊ตญ INNER๋ LEFT ๋ ๊ฐ๋ง ์ฃผ๋ก ์ฐ๊ฒ ๋๋๋ผ๊ณ ์ ๐
๐ ์์ ํ ์ด๋ธ
students ํ ์ด๋ธ
| id | name | grade | score | teacher_id |
|---|---|---|---|---|
| 1 | ๊น์ฒ ์ | 1 | 85 | 1 |
| 2 | ์ด์ํฌ | 2 | NULL | 1 |
| 3 | ๋ฐ๋ฏผ์ค | 1 | 90 | 2 |
| 4 | ์ต์ง์ | 3 | 72 | NULL |
| 5 | ์ ์ํ | 2 | NULL | 2 |
| 6 | ํ์ง๋ฏผ | 1 | 78 | 1 |
| 7 | ์ค์์ค | 3 | 95 | 2 |
| 8 | ๊ฐ๋ค์ | 2 | 88 | 1 |
| 9 | ์ํ์ฐ | 3 | NULL | 2 |
| 10 | ์ค์ง์ | 1 | 65 | NULL |
teachers ํ ์ด๋ธ
| id | name | subject |
|---|---|---|
| 1 | ๊น์ ์ | ์ํ |
| 2 | ์ด์ ์ | ์์ด |
| 3 | ๋ฐ์ ์ | ๊ณผํ |
CREATE DATABASE IF NOT EXISTS practice;
USE practice;
DROP TABLE IF EXISTS students;
DROP TABLE IF EXISTS teachers;
CREATE TABLE teachers (
id INT,
name VARCHAR(10),
subject VARCHAR(10)
);
CREATE TABLE students (
id INT,
name VARCHAR(10),
grade INT,
score INT,
teacher_id INT
);
INSERT INTO teachers VALUES (1, '๊น์ ์', '์ํ');
INSERT INTO teachers VALUES (2, '์ด์ ์', '์์ด');
INSERT INTO teachers VALUES (3, '๋ฐ์ ์', '๊ณผํ');
INSERT INTO students VALUES (1, '๊น์ฒ ์', 1, 85, 1);
INSERT INTO students VALUES (2, '์ด์ํฌ', 2, NULL, 1);
INSERT INTO students VALUES (3, '๋ฐ๋ฏผ์ค', 1, 90, 2);
INSERT INTO students VALUES (4, '์ต์ง์', 3, 72, NULL);
INSERT INTO students VALUES (5, '์ ์ํ', 2, NULL, 2);
INSERT INTO students VALUES (6, 'ํ์ง๋ฏผ', 1, 78, 1);
INSERT INTO students VALUES (7, '์ค์์ค', 3, 95, 2);
INSERT INTO students VALUES (8, '๊ฐ๋ค์', 2, 88, 1);
INSERT INTO students VALUES (9, '์ํ์ฐ', 3, NULL, 2);
INSERT INTO students VALUES (10, '์ค์ง์', 1, 65, NULL);
โผ๏ธ ์ด ๋ ํ ์ด๋ธ์ ๊ธฐ์ค์ผ๋ก JOIN ์์๋ฅผ ์ค๋ช ํฉ๋๋ค.
students.teacher_id์teachers.id๊ฐ ์ฐ๊ฒฐ ๊ธฐ์ค์ ๋๋ค.
๐ JOIN์ด๋?
JOIN์ ๋ ๊ฐ ์ด์์ ํ
์ด๋ธ์์ ๊ด๋ จ ์ปฌ๋ผ์ ๊ธฐ์ค์ผ๋ก ํ์ ๊ฒฐํฉํ๋ ์ ์
๋๋ค.
์ด๋ค JOIN์ ์ฐ๋๋์ ๋ฐ๋ผ ์กฐ๊ฑด์ ๋ง์ง ์๋ ํ์ ์ด๋ป๊ฒ ์ฒ๋ฆฌํ ์ง๊ฐ ๋ฌ๋ผ์ง๋๋ค.
๐ ๊ธฐ๋ณธ ๋ฌธ๋ฒ
SELECT ์ปฌ๋ผ
FROM ํ
์ด๋ธA
[INNER | LEFT | RIGHT | FULL] JOIN ํ
์ด๋ธB ON ํ
์ด๋ธA.์ปฌ๋ผ = ํ
์ด๋ธB.์ปฌ๋ผ;
โน๏ธ INNER vs OUTER
INNER JOIN
์กฐ๊ฑด์ ๋ง์กฑํ๋ ํ๋ง ๋ฐํํฉ๋๋ค.
OUTER JOIN
์กฐ๊ฑด ๋ถ์ผ์น ํ๋ ๋ฐ๊นฅ(outer)๊น์ง ํฌํจํฉ๋๋ค.
LEFT / RIGHT / FULL JOIN์ ๋ชจ๋ OUTER JOIN์ ์ผ์ข
์ด๋ฉฐ, OUTER ํค์๋๋ ์๋ต ๊ฐ๋ฅํฉ๋๋ค.
๐น INNER JOIN
ON ์กฐ๊ฑด์ ๋ง์กฑํ๋ ํ๋ง ๊ฒฐ๊ณผ์ ํฌํจ๋ฉ๋๋ค. ์กฐ๊ฑด์ ๋ง์ง ์๋ ํ์ ์์ชฝ ๋ชจ๋ ์ ์ธ๋ฉ๋๋ค.
ํ์๊ณผ ๋ด๋น ์ ์๋์ด ๋ชจ๋ ์๋ ๊ฒฝ์ฐ๋ง ์กฐํ
SELECT s.name, t.name AS ๋ด๋น์ ์๋
FROM students s
INNER JOIN teachers t ON s.teacher_id = t.id;
๐ก INNER ์๋ต ๊ฐ๋ฅ
SELECT s.name, t.name AS ๋ด๋น์ ์๋
FROM students s
JOIN teachers t ON s.teacher_id = t.id;
๊ธฐ๋ณธ์ ์ผ๋ก
ON์กฐ๊ฑด์ ๋ช ์ํ๋ฉดINNER JOIN์ผ๋ก ๋์ํฉ๋๋ค.
๐ฅ ๊ฒฐ๊ณผ
| name | ๋ด๋น์ ์๋ |
|---|---|
| ๊น์ฒ ์ | ๊น์ ์ |
| ์ด์ํฌ | ๊น์ ์ |
| ๋ฐ๋ฏผ์ค | ์ด์ ์ |
| ์ ์ํ | ์ด์ ์ |
| ํ์ง๋ฏผ | ๊น์ ์ |
| ์ค์์ค | ์ด์ ์ |
| ๊ฐ๋ค์ | ๊น์ ์ |
| ์ํ์ฐ | ์ด์ ์ |
์ต์ง์, ์ค์ง์๋ teacher_id๊ฐ NULL์ด๋ผ ์ ์ธ๋ฉ๋๋ค.
๋ฐ์ ์๋ ๋ด๋น ํ์์ด ์์ด ์ ์ธ๋ฉ๋๋ค.
๐น LEFT JOIN
์ผ์ชฝ ํ
์ด๋ธ(students)์ ๋ชจ๋ ํ์ ๋ฐํํ๊ณ ,
์ค๋ฅธ์ชฝ ํ
์ด๋ธ(teachers)์ ์ผ์นํ๋ ๊ฐ์ด ์์ผ๋ฉด NULL๋ก ์ฑ์๋๋ค.
ํ์์ ๋ค ๋ณด์ฌ์ฃผ๋, ๋ด๋น ์ ์๋์ด ์์ผ๋ฉด NULL๋ก ์ฑ์ฐ๊ธฐ
SELECT s.name, t.name AS ๋ด๋น์ ์๋
FROM students s
LEFT JOIN teachers t ON s.teacher_id = t.id;
๐ฅ ๊ฒฐ๊ณผ
| name | ๋ด๋น์ ์๋ |
|---|---|
| ๊น์ฒ ์ | ๊น์ ์ |
| ์ด์ํฌ | ๊น์ ์ |
| ๋ฐ๋ฏผ์ค | ์ด์ ์ |
| ์ต์ง์ | NULL |
| ์ ์ํ | ์ด์ ์ |
| ํ์ง๋ฏผ | ๊น์ ์ |
| ์ค์์ค | ์ด์ ์ |
| ๊ฐ๋ค์ | ๊น์ ์ |
| ์ํ์ฐ | ์ด์ ์ |
| ์ค์ง์ | NULL |
์ต์ง์, ์ค์ง์๋ ๋ด๋น ์ ์๋์ด ์์ง๋ง ๊ฒฐ๊ณผ์ ํฌํจ๋ฉ๋๋ค. ์ค๋ฌด์์ ๊ฐ์ฅ ์์ฃผ ์ฐ๋ JOIN์ ๋๋ค.
๐น RIGHT JOIN
์ค๋ฅธ์ชฝ ํ
์ด๋ธ(teachers)์ ๋ชจ๋ ํ์ ๋ฐํํ๊ณ ,
์ผ์ชฝ ํ
์ด๋ธ(students)์ ์ผ์นํ๋ ๊ฐ์ด ์์ผ๋ฉด NULL๋ก ์ฑ์๋๋ค.
์ ์๋์ ๋ค ๋ณด์ฌ์ฃผ๋, ๋ด๋น ํ์์ด ์์ผ๋ฉด NULL
SELECT s.name, t.name AS ๋ด๋น์ ์๋
FROM students s
RIGHT JOIN teachers t ON s.teacher_id = t.id;
๐ฅ ๊ฒฐ๊ณผ
| name | ๋ด๋น์ ์๋ |
|---|---|
| ๊น์ฒ ์ | ๊น์ ์ |
| ์ด์ํฌ | ๊น์ ์ |
| ํ์ง๋ฏผ | ๊น์ ์ |
| ๊ฐ๋ค์ | ๊น์ ์ |
| ๋ฐ๋ฏผ์ค | ์ด์ ์ |
| ์ ์ํ | ์ด์ ์ |
| ์ค์์ค | ์ด์ ์ |
| ์ํ์ฐ | ์ด์ ์ |
| NULL | ๋ฐ์ ์ |
๋ฐ์ ์์ ๋ด๋น ํ์์ด ์์ง๋ง ๊ฒฐ๊ณผ์ ํฌํจ๋ฉ๋๋ค.
๐น FULL JOIN
๋ ํ
์ด๋ธ์ ๋ชจ๋ ํ์ ๋ฐํํ๊ณ , ์ผ์นํ์ง ์๋ ์ชฝ์ NULL๋ก ์ฑ์๋๋ค.
LEFT JOIN๊ณผ RIGHT JOIN ์ ํฉ์น ๊ฒฐ๊ณผ์
๋๋ค.
ํ์๊ณผ ์ ์๋ ๋ชจ๋ ๋น ์ง์์ด ์กฐํ
SELECT s.name, t.name AS ๋ด๋น์ ์๋
FROM students s
FULL JOIN teachers t ON s.teacher_id = t.id;
๐ฅ ๊ฒฐ๊ณผ
| name | ๋ด๋น์ ์๋ |
|---|---|
| ๊น์ฒ ์ | ๊น์ ์ |
| ์ด์ํฌ | ๊น์ ์ |
| ๋ฐ๋ฏผ์ค | ์ด์ ์ |
| ์ต์ง์ | NULL |
| ์ ์ํ | ์ด์ ์ |
| ํ์ง๋ฏผ | ๊น์ ์ |
| ์ค์์ค | ์ด์ ์ |
| ๊ฐ๋ค์ | ๊น์ ์ |
| ์ํ์ฐ | ์ด์ ์ |
| ์ค์ง์ | NULL |
| NULL | ๋ฐ์ ์ |
โ ๏ธ FULL JOIN ๋ฐ์ดํฐ๋ฒ ์ด์ค๋ณ ์ง์ ์ฌ๋ถ
| ๋ฐ์ดํฐ๋ฒ ์ด์ค | ์ง์ ์ฌ๋ถ | ๋ฏธ์ง์ ์ ๋์ |
|---|---|---|
| PostgreSQL | โ ์ง์ | - |
| SQL Server | โ ์ง์ | - |
| Oracle | โ ์ง์ | - |
| MySQL | โ ๋ฏธ์ง์ | LEFT JOIN + UNION + RIGHT JOIN |
| MariaDB | โ ๋ฏธ์ง์ | LEFT JOIN + UNION + RIGHT JOIN |
| SQLite | โ ๋ฏธ์ง์ | LEFT JOIN + UNION + RIGHT JOIN |
๐น CROSS JOIN
๋ ํ
์ด๋ธ์ ๋ชจ๋ ํ์ ์กฐํฉํด ๋ฐํํฉ๋๋ค.ON ์กฐ๊ฑด ์์ด ๋ชจ๋ ์กฐํฉ์ ๋ง๋ค๊ธฐ ๋๋ฌธ์ ๊ฒฐ๊ณผ ํ ์๋ ํ
์ด๋ธA ํ ์ ร ํ
์ด๋ธB ํ ์๊ฐ ๋ฉ๋๋ค.
๋ชจ๋ ํ์๊ณผ ๋ชจ๋ ์ ์๋์ ์กฐํฉ ์กฐํ
SELECT s.name, t.name AS ์ ์๋
FROM students s
CROSS JOIN teachers t;
๐ฅ ๊ฒฐ๊ณผ (์ผ๋ถ) - ์ด 30ํ
| name | ์ ์๋ |
|---|---|
| ๊น์ฒ ์ | ๊น์ ์ |
| ๊น์ฒ ์ | ์ด์ ์ |
| ๊น์ฒ ์ | ๋ฐ์ ์ |
| ์ด์ํฌ | ๊น์ ์ |
| ์ด์ํฌ | ์ด์ ์ |
| ... | ... |
โน๏ธ CROSS JOIN์ ON ์กฐ๊ฑด์ ์ถ๊ฐํ๋ฉด?
CROSS JOIN์ WHERE๋ก ์กฐ๊ฑด์ ์ถ๊ฐํ๋ฉด INNER JOIN๊ณผ ๋์ผํ ๊ฒฐ๊ณผ๊ฐ ๋์ต๋๋ค.
-- ์ด ๋ ์ฟผ๋ฆฌ๋ ๊ฒฐ๊ณผ๊ฐ ๋์ผํฉ๋๋ค
SELECT s.name, t.name FROM students s CROSS JOIN teachers t WHERE s.teacher_id = t.id;
SELECT s.name, t.name FROM students s JOIN teachers t ON s.teacher_id = t.id;
์กฐ๊ฑด์ด ํ์ํ๋ค๋ฉด ์๋๊ฐ ๋ช
ํํ INNER JOIN์ ์ฐ๋ ๊ฒ ์ข์ต๋๋ค.
๐น SELF JOIN
๊ฐ์ ํ
์ด๋ธ์ ๋ ๋ฒ ์ฐธ์กฐํด ์๊ธฐ ์์ ๊ณผ JOINํฉ๋๋ค.
๋ฐ๋์ ๋ณ์นญ(alias)์ ๋ค๋ฅด๊ฒ ์ค์ผ ํฉ๋๋ค.
๊ฐ์ ์ ์๋์ ๋ด๋น์ผ๋ก ๋ ํ์๋ผ๋ฆฌ ์กฐํ
SELECT s1.name AS ํ์1, s2.name AS ํ์2, s1.teacher_id
FROM students s1
JOIN students s2
ON s1.teacher_id = s2.teacher_id
AND s1.id < s2.id;
๐ฅ ๊ฒฐ๊ณผ
| ํ์1 | ํ์2 | teacher_id |
|---|---|---|
| ๊น์ฒ ์ | ์ด์ํฌ | 1 |
| ๊น์ฒ ์ | ํ์ง๋ฏผ | 1 |
| ๊น์ฒ ์ | ๊ฐ๋ค์ | 1 |
| ์ด์ํฌ | ํ์ง๋ฏผ | 1 |
| ์ด์ํฌ | ๊ฐ๋ค์ | 1 |
| ํ์ง๋ฏผ | ๊ฐ๋ค์ | 1 |
| ๋ฐ๋ฏผ์ค | ์ ์ํ | 2 |
| ๋ฐ๋ฏผ์ค | ์ค์์ค | 2 |
| ๋ฐ๋ฏผ์ค | ์ํ์ฐ | 2 |
| ์ ์ํ | ์ค์์ค | 2 |
| ์ ์ํ | ์ํ์ฐ | 2 |
| ์ค์์ค | ์ํ์ฐ | 2 |
s1.id < s2.id ์กฐ๊ฑด์ ์ถ๊ฐํ์ง ์์ผ๋ฉด ๊น์ฒ ์-์ด์ํฌ, ์ด์ํฌ-๊น์ฒ ์์ฒ๋ผ ์์๋ง ๋ค๋ฅธ ์ค๋ณต ์๊ณผ ์๊ธฐ ์์ ๊ณผ์ ์๋ ๊ฒฐ๊ณผ์ ํฌํจ๋ฉ๋๋ค.
โ ๋ง๋ฌด๋ฆฌ
| JOIN | ํฌํจ๋๋ ๋ฐ์ดํฐ |
|---|---|
| INNER JOIN | ON ์กฐ๊ฑด์ ๋ง์กฑํ๋ ํ๋ง |
| LEFT JOIN | ์ผ์ชฝ ํ ์ด๋ธ ์ ์ฒด + ์ค๋ฅธ์ชฝ ์ผ์น ํ |
| RIGHT JOIN | ์ค๋ฅธ์ชฝ ํ ์ด๋ธ ์ ์ฒด + ์ผ์ชฝ ์ผ์น ํ |
| FULL JOIN | ๋ ํ ์ด๋ธ ์ ์ฒด |
| CROSS JOIN | ๋ ํ ์ด๋ธ์ ๋ชจ๋ ์กฐํฉ |
| SELF JOIN | ๊ฐ์ ํ ์ด๋ธ๋ผ๋ฆฌ ์ฐ๊ฒฐ |
๐ ์ฐธ๊ณ ์๋ฃ
'Database > SQL ๊ธฐ์ด' ์นดํ ๊ณ ๋ฆฌ์ ๋ค๋ฅธ ๊ธ
| SQL ๊ธฐ์ด - IN, EXISTS, ANY, ALL (0) | 2026.03.31 |
|---|---|
| SQL ๊ธฐ์ด - ์๋ธ์ฟผ๋ฆฌ(Subquery) (0) | 2026.03.31 |
| SQL ๊ธฐ์ด - CASE (0) | 2026.03.23 |
| SQL ๊ธฐ์ด - BETWEEN, LIKE, IN (0) | 2026.03.21 |
| SQL ๊ธฐ์ด - WHERE (0) | 2026.03.20 |