Database/SQL ๊ธฐ์ดˆ

SQL ๊ธฐ์ดˆ - JOIN

UNarD 2026. 3. 27. 16:44

๐Ÿ”— 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