JOIN
JOIN¶
1. JOIN κ°λ ¶
JOINμ λ κ° μ΄μμ ν μ΄λΈμ μ°κ²°νμ¬ λ°μ΄ν°λ₯Ό μ‘°ννλ λ°©λ²μ λλ€.
βββββββββββββββββββ βββββββββββββββββββ
β users β β orders β
βββββββββββββββββββ€ βββββββββββββββββββ€
β id β name β β id β user_id β
ββββββΌβββββββββββββ€ ββββββΌβββββββββββββ€
β 1 β κΉμ² μ βββββββ 1 β 1 β
β 2 β μ΄μν¬ βββββββ 2 β 1 β
β 3 β λ°λ―Όμ β β 3 β 2 β
ββββββ΄βββββββββββββ ββββββ΄βββββββββββββ
β users.id = orders.user_id
2. μ€μ΅ ν μ΄λΈ μ€λΉ¶
-- μ¬μ©μ ν
μ΄λΈ
CREATE TABLE users (
id SERIAL PRIMARY KEY,
name VARCHAR(100) NOT NULL,
email VARCHAR(255)
);
-- μ£Όλ¬Έ ν
μ΄λΈ
CREATE TABLE orders (
id SERIAL PRIMARY KEY,
user_id INTEGER REFERENCES users(id),
product_name VARCHAR(200),
amount NUMERIC(10, 2),
order_date DATE DEFAULT CURRENT_DATE
);
-- μν λ°μ΄ν°
INSERT INTO users (name, email) VALUES
('κΉμ² μ', 'kim@email.com'),
('μ΄μν¬', 'lee@email.com'),
('λ°λ―Όμ', 'park@email.com'),
('μ΅μ§μ', 'choi@email.com'); -- μ£Όλ¬Έ μλ μ¬μ©μ
INSERT INTO orders (user_id, product_name, amount) VALUES
(1, 'λ
ΈνΈλΆ', 1500000),
(1, 'λ§μ°μ€', 50000),
(2, 'ν€λ³΄λ', 100000),
(2, 'λͺ¨λν°', 300000),
(3, 'ν€λμ
', 150000),
(NULL, 'μ λ¬ΌμΈνΈ', 80000); -- νμ μλ μ£Όλ¬Έ
3. INNER JOIN¶
μμͺ½ ν μ΄λΈ λͺ¨λμ μΌμΉνλ λ°μ΄ν°λ§ λ°νν©λλ€.
-- κΈ°λ³Έ λ¬Έλ²
SELECT columns
FROM table1
INNER JOIN table2 ON table1.column = table2.column;
-- μ¬μ©μμ μ£Όλ¬Έ μ 보 μ‘°ν
SELECT
users.name,
users.email,
orders.product_name,
orders.amount
FROM users
INNER JOIN orders ON users.id = orders.user_id;
κ²°κ³Ό:
name β email β product_name β amount
βββββββββΌβββββββββββββββββββΌβββββββββββββββΌββββββββββ
κΉμ² μ β kim@email.com β λ
ΈνΈλΆ β 1500000
κΉμ² μ β kim@email.com β λ§μ°μ€ β 50000
μ΄μν¬ β lee@email.com β ν€λ³΄λ β 100000
μ΄μν¬ β lee@email.com β λͺ¨λν° β 300000
λ°λ―Όμ β park@email.com β ν€λμ
β 150000
ν μ΄λΈ λ³μΉ μ¬μ©¶
SELECT u.name, o.product_name, o.amount
FROM users u
INNER JOIN orders o ON u.id = o.user_id;
JOINλ§ μ°λ©΄ INNER JOIN¶
-- INNER μλ΅ κ°λ₯
SELECT u.name, o.product_name
FROM users u
JOIN orders o ON u.id = o.user_id;
4. LEFT (OUTER) JOIN¶
μΌμͺ½ ν μ΄λΈμ λͺ¨λ ν + μ€λ₯Έμͺ½μμ μΌμΉνλ νμ λ°νν©λλ€. μΌμΉνμ§ μμΌλ©΄ NULLλ‘ μ±μμ§λλ€.
SELECT
u.name,
o.product_name,
o.amount
FROM users u
LEFT JOIN orders o ON u.id = o.user_id;
κ²°κ³Ό:
name β product_name β amount
βββββββββΌβββββββββββββββΌββββββββββ
κΉμ² μ β λ
ΈνΈλΆ β 1500000
κΉμ² μ β λ§μ°μ€ β 50000
μ΄μν¬ β ν€λ³΄λ β 100000
μ΄μν¬ β λͺ¨λν° β 300000
λ°λ―Όμ β ν€λμ
β 150000
μ΅μ§μ β NULL β NULL β μ£Όλ¬Έ μλ μ¬μ©μλ ν¬ν¨
μ£Όλ¬Έ μλ μ¬μ©μλ§ μ°ΎκΈ°¶
SELECT u.name, u.email
FROM users u
LEFT JOIN orders o ON u.id = o.user_id
WHERE o.id IS NULL;
5. RIGHT (OUTER) JOIN¶
μ€λ₯Έμͺ½ ν μ΄λΈμ λͺ¨λ ν + μΌμͺ½μμ μΌμΉνλ νμ λ°νν©λλ€.
SELECT
u.name,
o.product_name,
o.amount
FROM users u
RIGHT JOIN orders o ON u.id = o.user_id;
κ²°κ³Ό:
name β product_name β amount
βββββββββΌβββββββββββββββΌββββββββββ
κΉμ² μ β λ
ΈνΈλΆ β 1500000
κΉμ² μ β λ§μ°μ€ β 50000
μ΄μν¬ β ν€λ³΄λ β 100000
μ΄μν¬ β λͺ¨λν° β 300000
λ°λ―Όμ β ν€λμ
β 150000
NULL β μ λ¬ΌμΈνΈ β 80000 β νμ μλ μ£Όλ¬Έλ ν¬ν¨
6. FULL (OUTER) JOIN¶
μμͺ½ ν μ΄λΈμ λͺ¨λ νμ λ°νν©λλ€. μΌμΉνμ§ μμΌλ©΄ NULLλ‘ μ±μμ§λλ€.
SELECT
u.name,
o.product_name,
o.amount
FROM users u
FULL JOIN orders o ON u.id = o.user_id;
κ²°κ³Ό:
name β product_name β amount
βββββββββΌβββββββββββββββΌββββββββββ
κΉμ² μ β λ
ΈνΈλΆ β 1500000
κΉμ² μ β λ§μ°μ€ β 50000
μ΄μν¬ β ν€λ³΄λ β 100000
μ΄μν¬ β λͺ¨λν° β 300000
λ°λ―Όμ β ν€λμ
β 150000
μ΅μ§μ β NULL β NULL β μ£Όλ¬Έ μλ μ¬μ©μ
NULL β μ λ¬ΌμΈνΈ β 80000 β νμ μλ μ£Όλ¬Έ
7. CROSS JOIN¶
λͺ¨λ κ°λ₯ν μ‘°ν©μ λ°νν©λλ€ (μΉ΄ν°μ κ³±).
-- μμκ³Ό μ¬μ΄μ¦ ν
μ΄λΈ
CREATE TABLE colors (name VARCHAR(20));
CREATE TABLE sizes (name VARCHAR(10));
INSERT INTO colors VALUES ('λΉ¨κ°'), ('νλ'), ('κ²μ ');
INSERT INTO sizes VALUES ('S'), ('M'), ('L');
-- λͺ¨λ μ‘°ν©
SELECT c.name AS color, s.name AS size
FROM colors c
CROSS JOIN sizes s;
κ²°κ³Ό:
color β size
ββββββββΌββββββ
λΉ¨κ° β S
λΉ¨κ° β M
λΉ¨κ° β L
νλ β S
νλ β M
νλ β L
κ²μ β S
κ²μ β M
κ²μ β L
8. SELF JOIN (μκΈ° μ‘°μΈ)¶
κ°μ ν μ΄λΈμ μκΈ° μμ κ³Ό μ‘°μΈν©λλ€.
-- μ§μ-κ΄λ¦¬μ κ΄κ³
CREATE TABLE employees (
id SERIAL PRIMARY KEY,
name VARCHAR(100),
manager_id INTEGER REFERENCES employees(id)
);
INSERT INTO employees (name, manager_id) VALUES
('λνμ΄μ¬', NULL),
('λΆμ₯', 1),
('κ³Όμ₯A', 2),
('κ³Όμ₯B', 2),
('μ¬μ', 3);
-- μ§μκ³Ό κ΄λ¦¬μ μ΄λ¦ μ‘°ν
SELECT
e.name AS μ§μ,
m.name AS κ΄λ¦¬μ
FROM employees e
LEFT JOIN employees m ON e.manager_id = m.id;
κ²°κ³Ό:
μ§μ β κ΄λ¦¬μ
ββββββββββΌβββββββββ
λνμ΄μ¬ β NULL
λΆμ₯ β λνμ΄μ¬
κ³Όμ₯A β λΆμ₯
κ³Όμ₯B β λΆμ₯
μ¬μ β κ³Όμ₯A
9. λ€μ€ ν μ΄λΈ JOIN¶
3κ° μ΄μμ ν μ΄λΈμ μ°κ²°ν©λλ€.
-- μΉ΄ν
κ³ λ¦¬ ν
μ΄λΈ μΆκ°
CREATE TABLE categories (
id SERIAL PRIMARY KEY,
name VARCHAR(100)
);
-- μν ν
μ΄λΈ
CREATE TABLE products (
id SERIAL PRIMARY KEY,
category_id INTEGER REFERENCES categories(id),
name VARCHAR(200),
price NUMERIC(10, 2)
);
-- μ£Όλ¬Έ μμΈ ν
μ΄λΈ
CREATE TABLE order_items (
id SERIAL PRIMARY KEY,
order_id INTEGER REFERENCES orders(id),
product_id INTEGER REFERENCES products(id),
quantity INTEGER
);
-- 3κ° ν
μ΄λΈ JOIN
SELECT
u.name AS user_name,
p.name AS product_name,
c.name AS category_name,
oi.quantity
FROM users u
JOIN orders o ON u.id = o.user_id
JOIN order_items oi ON o.id = oi.order_id
JOIN products p ON oi.product_id = p.id
JOIN categories c ON p.category_id = c.id;
10. JOIN 쑰건과 WHERE¶
ON vs WHERE¶
-- ON: ν
μ΄λΈ μ°κ²° 쑰건
-- WHERE: κ²°κ³Ό νν°λ§
-- LEFT JOIN + WHERE
SELECT u.name, o.product_name, o.amount
FROM users u
LEFT JOIN orders o ON u.id = o.user_id
WHERE o.amount > 100000; -- NULL ν μ κ±°λ¨
-- LEFT JOIN + ONμ μΆκ° 쑰건
SELECT u.name, o.product_name, o.amount
FROM users u
LEFT JOIN orders o ON u.id = o.user_id AND o.amount > 100000;
-- λͺ¨λ μ¬μ©μ μ μ§, 쑰건 λ§λ μ£Όλ¬Έλ§ μ°κ²°
λ³΅ν© JOIN 쑰건¶
SELECT *
FROM table1 t1
JOIN table2 t2 ON t1.col1 = t2.col1 AND t1.col2 = t2.col2;
11. USING μ ¶
λμΌν 컬λΌλͺ μΌλ‘ μ‘°μΈν λ κ°λ¨νκ² ννν©λλ€.
-- ON μ¬μ©
SELECT * FROM orders o
JOIN users u ON o.user_id = u.id;
-- USING μ¬μ© (컬λΌλͺ
μ΄ κ°μ λ)
-- orders.user_idμ users.user_idκ° κ°λ€λ©΄:
SELECT * FROM orders
JOIN users USING (user_id);
12. NATURAL JOIN¶
λμΌν μ΄λ¦μ λͺ¨λ 컬λΌμΌλ‘ μλ μ‘°μΈν©λλ€. (κΆμ₯νμ§ μμ)
-- κ°μ μ΄λ¦μ λͺ¨λ 컬λΌμΌλ‘ μ‘°μΈ
SELECT * FROM orders
NATURAL JOIN users;
-- μλμΉ μμ κ²°κ³Όκ° λμ¬ μ μμ΄ λͺ
μμ ON κΆμ₯
13. JOIN μκ°ν¶
INNER JOIN: LEFT JOIN: RIGHT JOIN: FULL JOIN:
βββββ βββββ βββββ βββββ
ββΌββββΌβ ββΌββββΌβ ββΌββββΌβ ββΌββββΌβ
ββΌββββββΌβ ββΌβββββ β β ββββββΌβ ββΌββββββΌβ
β βββββ β βββββββ β β βββββββ βββββββββ
ββΌββββββΌβ ββΌβββββ β β ββββββΌβ ββΌββββββΌβ
ββΌββββΌβ ββΌββββ β β βββββΌβ βββββββΌβ
βββββ βββββββ βββββββ βββββββ
A β© B A μ 체 B μ 체 A βͺ B
14. μ€μ΅ μμ ¶
μ€μ΅ 1: κΈ°λ³Έ JOIN¶
-- 1. μ£Όλ¬Έν μ μλ μ¬μ©μμ μ£Όλ¬Έ μ 보
SELECT u.name, o.product_name, o.amount, o.order_date
FROM users u
INNER JOIN orders o ON u.id = o.user_id
ORDER BY o.order_date DESC;
-- 2. κ° μ¬μ©μλ³ μ΄ μ£Όλ¬Έ κΈμ‘
SELECT u.name, SUM(o.amount) AS total_amount
FROM users u
INNER JOIN orders o ON u.id = o.user_id
GROUP BY u.id, u.name
ORDER BY total_amount DESC;
μ€μ΅ 2: OUTER JOIN¶
-- 1. λͺ¨λ μ¬μ©μ (μ£Όλ¬Έ μ¬λΆ κ΄κ³μμ΄)
SELECT
u.name,
COALESCE(SUM(o.amount), 0) AS total_amount,
COUNT(o.id) AS order_count
FROM users u
LEFT JOIN orders o ON u.id = o.user_id
GROUP BY u.id, u.name
ORDER BY total_amount DESC;
-- 2. μ£Όλ¬Ένμ§ μμ μ¬μ©μ μ°ΎκΈ°
SELECT u.name, u.email
FROM users u
LEFT JOIN orders o ON u.id = o.user_id
WHERE o.id IS NULL;
-- 3. νμμ΄ μλ μ£Όλ¬Έ μ°ΎκΈ°
SELECT o.id, o.product_name, o.amount
FROM users u
RIGHT JOIN orders o ON u.id = o.user_id
WHERE u.id IS NULL;
μ€μ΅ 3: λ³΅ν© μ‘°κ±΄ JOIN¶
-- 1. 100λ§μ μ΄μ μ£Όλ¬Έν μ¬μ©μ
SELECT DISTINCT u.name, u.email
FROM users u
INNER JOIN orders o ON u.id = o.user_id
WHERE o.amount >= 1000000;
-- 2. μ΅κ·Ό 30μΌ μ΄λ΄ μ£Όλ¬Έν μ¬μ©μ
SELECT DISTINCT u.name
FROM users u
INNER JOIN orders o ON u.id = o.user_id
WHERE o.order_date >= CURRENT_DATE - INTERVAL '30 days';
μ€μ΅ 4: μ¬λ¬ ν μ΄λΈ JOIN¶
-- μΉ΄ν
κ³ λ¦¬ β μν β μ£Όλ¬Έ μ°κ²°
SELECT
c.name AS category,
p.name AS product,
u.name AS customer,
oi.quantity,
p.price * oi.quantity AS subtotal
FROM categories c
JOIN products p ON c.id = p.category_id
JOIN order_items oi ON p.id = oi.product_id
JOIN orders o ON oi.order_id = o.id
JOIN users u ON o.user_id = u.id
ORDER BY c.name, p.name;
15. μ±λ₯ κ³ λ €μ¬ν¶
μΈλ±μ€ νμ©¶
-- μΈλν€ μ»¬λΌμ μΈλ±μ€ μμ±
CREATE INDEX idx_orders_user_id ON orders(user_id);
CREATE INDEX idx_order_items_order_id ON order_items(order_id);
CREATE INDEX idx_order_items_product_id ON order_items(product_id);
νμν 컬λΌλ§ SELECT¶
-- λμ μ
SELECT * FROM users u JOIN orders o ON u.id = o.user_id;
-- μ’μ μ
SELECT u.name, o.product_name, o.amount
FROM users u JOIN orders o ON u.id = o.user_id;
EXPLAINμΌλ‘ μ€ν κ³ν νμΈ¶
EXPLAIN SELECT u.name, o.product_name
FROM users u
JOIN orders o ON u.id = o.user_id;
λ€μ λ¨κ³¶
07_Aggregation_and_Grouping.mdμμ μ§κ³ ν¨μμ GROUP BYλ₯Ό λ°°μλ΄ μλ€!