2025-08-16 01:49
Tags:

๐ SQL ์ฐธ์กฐ(Reference)์ ๋ชจ๋ ๊ฒ: ๋ฐ์ดํฐ๋ฒ ์ด์ค ๊ด๊ณ์ ์์ ํ ํธ๋๋ถ ๊ฐ์ด๋
๐ ๋ค์ด๊ฐ๋ฉฐ
๋ฐ์ดํฐ๋ฒ ์ด์ค์์ **์ฐธ์กฐ(Reference)**๋ผ๋ ๊ฐ๋ ์ ํ ์ด๋ธ ๊ฐ์ ๊ด๊ณ๋ฅผ ์ ์ํ๊ณ ๋ฐ์ดํฐ ๋ฌด๊ฒฐ์ฑ์ ๋ณด์ฅํ๋ ํต์ฌ ๋ฉ์ปค๋์ฆ์ ๋๋ค. ๋ง์น ๋์๊ด์์ ์ฑ ์ ์ฐพ๊ธฐ ์ํด ๋์ ๋ชฉ๋ก์ ์ฐธ์กฐํ๋ฏ์ด, SQL ๋ฐ์ดํฐ๋ฒ ์ด์ค์์๋ ํ ํ ์ด๋ธ์ ๋ฐ์ดํฐ๊ฐ ๋ค๋ฅธ ํ ์ด๋ธ์ ํน์ ๋ฐ์ดํฐ๋ฅผ ์ฐธ์กฐํจ์ผ๋ก์จ ๋ ผ๋ฆฌ์ ์ธ ์ฐ๊ฒฐ๊ณ ๋ฆฌ๋ฅผ ๋ง๋ค์ด๋ ๋๋ค.12
SQL์์ ์ฐธ์กฐ๋ ์ฃผ๋ก ์ธ๋ ํค(Foreign Key) ์ ์ฝ์กฐ๊ฑด์ ํตํด ๊ตฌํ๋๋ฉฐ, ์ด๋ ๋ฐ์ดํฐ๋ฒ ์ด์ค ์ค๊ณ์ ๊ธฐ์ด๊ฐ ๋๋ ๊ด๊ณํ ๋ชจ๋ธ์ ํต์ฌ ์๋ฆฌ์ ๋๋ค. ์ด ํธ๋๋ถ์ SQL ์ฐธ์กฐ์ ๋ชจ๋ ์ธก๋ฉด์ ์ฒด๊ณ์ ์ผ๋ก ๋ค๋ฃจ์ด, ์ด๋ณด์๋ถํฐ ๊ณ ๊ธ ๊ฐ๋ฐ์๊น์ง ์ค๋ฌด์์ ๋ฐ๋ก ํ์ฉํ ์ ์๋ ์ค์ฉ์ ์ธ ์ง์์ ์ ๊ณตํฉ๋๋ค.
SQL ์ธ๋ ํค ๊ด๊ณ๋ฅผ ๋ณด์ฌ์ฃผ๋ ์ ์์๊ฑฐ๋ ๋ฐ์ดํฐ๋ฒ ์ด์ค ๊ตฌ์กฐ๋
๐ฏ SQL ์ฐธ์กฐ๊ฐ ๋ง๋ค์ด์ง ์ด์ ์ ๋ฐฐ๊ฒฝ
๋ฐ์ดํฐ ๋ฌด๊ฒฐ์ฑ์ ํ์์ฑ
SQL ์ฐธ์กฐ ์์คํ ์ ๊ด๊ณํ ๋ฐ์ดํฐ๋ฒ ์ด์ค์ ์๋ฒ์ง๋ก ๋ถ๋ฆฌ๋ Edgar F. Codd์ ๊ด๊ณํ ๋ชจ๋ธ์์ ์ถ๋ฐํ์ต๋๋ค. 1970๋ ๋ IBM์์ ๊ฐ๋ฐ๋ ์ด ๊ฐ๋ ์ ๋ค์๊ณผ ๊ฐ์ ํต์ฌ ๋ฌธ์ ๋ค์ ํด๊ฒฐํ๊ธฐ ์ํด ๋ง๋ค์ด์ก์ต๋๋ค:3
1. ๋ฐ์ดํฐ ์ค๋ณต์ฑ ๋ฌธ์
๊ธฐ์กด์ ํ์ผ ๊ธฐ๋ฐ ์์คํ ์์๋ ๊ฐ์ ์ ๋ณด๊ฐ ์ฌ๋ฌ ๊ณณ์ ์ ์ฅ๋์ด ์ผ๊ด์ฑ์ ์ ์งํ๊ธฐ ์ด๋ ค์ ์ต๋๋ค. ์๋ฅผ ๋ค์ด, ๊ณ ๊ฐ ์ ๋ณด๊ฐ ์ฃผ๋ฌธ ํ ์ด๋ธ๊ณผ ๋ฐฐ์ก ํ ์ด๋ธ์ ๊ฐ๊ฐ ์ ์ฅ๋๋ฉด, ๊ณ ๊ฐ์ด ์ฃผ์๋ฅผ ๋ณ๊ฒฝํ์ ๋ ๋ชจ๋ ๊ณณ์ ์ ๋ฐ์ดํธํด์ผ ํ์ฃ .4
2. ๊ณ ์ ๋ ์ฝ๋(Orphan Records) ๋ฐฉ์ง
์ฐธ์กฐ ๋ฌด๊ฒฐ์ฑ์ด ์๋ค๋ฉด ์กด์ฌํ์ง ์๋ ๊ณ ๊ฐ์ ๋ํ ์ฃผ๋ฌธ์ด๋ ์ญ์ ๋ ๋ถ์์ ์ํ ์ง์ ๊ฐ์ ๋ ผ๋ฆฌ์ ์ผ๋ก ๋ถ๊ฐ๋ฅํ ๋ฐ์ดํฐ๊ฐ ์์ฑ๋ ์ ์์ต๋๋ค.56
3. ๋ฐ์ดํฐ ์ผ๊ด์ฑ ๋ณด์ฅ
๋น์ฆ๋์ค ๊ท์น์ ๋ฐ์ดํฐ๋ฒ ์ด์ค ๋ ๋ฒจ์์ ๊ฐ์ ํจ์ผ๋ก์จ ์ ํ๋ฆฌ์ผ์ด์ ๋ก์ง์ ๋ณต์ก์ฑ์ ์ค์ด๊ณ , ๋ค์ํ ์ ํ๋ฆฌ์ผ์ด์ ์ด ๊ฐ์ ๋ฐ์ดํฐ๋ฒ ์ด์ค๋ฅผ ์ฌ์ฉํด๋ ์ผ๊ด์ฑ์ ์ ์งํ ์ ์๊ฒ ํ์ต๋๋ค.78
์ค์ ์ ๋ฌด์์์ ํ์์ฑ
ํ์ค ์ธ๊ณ์ ๋น์ฆ๋์ค๋ ๊ด๊ณ๋ก ์ด๋ฃจ์ด์ ธ ์์ต๋๋ค. ๊ณ ๊ฐ์ ์ฃผ๋ฌธ์ ํ๊ณ , ์ง์์ ๋ถ์์ ์์๋๋ฉฐ, ์ ํ์ ์นดํ ๊ณ ๋ฆฌ์ ๋ถ๋ฅ๋ฉ๋๋ค. ์ด๋ฌํ ๊ด๊ณ๋ฅผ ๋ฐ์ดํฐ๋ฒ ์ด์ค์ ์ ํํ ๋ฐ์ํ๊ณ ์ ์งํ๊ธฐ ์ํด ์ฐธ์กฐ ์์คํ ์ด ํ์์ ์ด์์ต๋๋ค.910
๐๏ธ SQL ์ฐธ์กฐ์ ํต์ฌ ๊ตฌ์กฐ์ ๊ฐ๋
์ธ๋ ํค(Foreign Key)์ ์ ์
์ธ๋ ํค๋ ํ ํ ์ด๋ธ์ ์ปฌ๋ผ์ด ๋ค๋ฅธ ํ ์ด๋ธ์ ๊ธฐ๋ณธ ํค๋ฅผ ์ฐธ์กฐํ๋ ์ ์ฝ์กฐ๊ฑด์ ๋๋ค. ์ด๋ ๋ ํ ์ด๋ธ ์ฌ์ด์ ๋ ผ๋ฆฌ์ ์ฐ๊ฒฐ์ ๋ง๋ค๊ณ , ๋ฐ์ดํฐ์ ์ฐธ์กฐ ๋ฌด๊ฒฐ์ฑ์ ๋ณด์ฅํฉ๋๋ค.211
-- ๊ธฐ๋ณธ ๊ตฌ์กฐ ์์
CREATE TABLE customers (
customer_id INT PRIMARY KEY,
name VARCHAR(50),
email VARCHAR(100)
);
CREATE TABLE orders (
order_id INT PRIMARY KEY,
customer_id INT,
order_date DATE,
FOREIGN KEY (customer_id) REFERENCES customers(customer_id)
);
์ฐธ์กฐ ๋ฌด๊ฒฐ์ฑ(Referential Integrity)์ ์๋ฆฌ
์ฐธ์กฐ ๋ฌด๊ฒฐ์ฑ์ ์ธ๋ ํค ๊ฐ์ด ์ ํจํ ๊ธฐ๋ณธ ํค ๊ฐ์ ์ฐธ์กฐํ๊ฑฐ๋ NULL์ด์ด์ผ ํ๋ค๋ ๊ท์น์ ๋๋ค. ์ด๋ ๋ค์ ๋ ๊ฐ์ง ์กฐ๊ฑด์ ๋ง์กฑํด์ผ ํฉ๋๋ค:34
-
์กด์ฌํ๋ ๊ฐ ์ฐธ์กฐ: ์ธ๋ ํค ๊ฐ์ ๋ฐ๋์ ๋ถ๋ชจ ํ ์ด๋ธ์ ๊ธฐ๋ณธ ํค์ ์กด์ฌํ๋ ๊ฐ์ด์ด์ผ ํฉ๋๋ค
-
NULL ํ์ฉ: ์ธ๋ ํค ์ปฌ๋ผ์ด NULL์ ํ์ฉํ๋ค๋ฉด, NULL ๊ฐ์ ๊ฐ์ง ์ ์์ต๋๋ค
๋ถ๋ชจ-์์ ํ ์ด๋ธ ๊ด๊ณ
SQL ์ฐธ์กฐ์์๋ **๋ถ๋ชจ ํ ์ด๋ธ(Parent Table)**๊ณผ **์์ ํ ์ด๋ธ(Child Table)**์ ๊ฐ๋ ์ด ์ค์ํฉ๋๋ค:212
-
๋ถ๋ชจ ํ ์ด๋ธ: ๊ธฐ๋ณธ ํค๋ฅผ ์ ๊ณตํ๋ ํ ์ด๋ธ (์: customers)
-
์์ ํ ์ด๋ธ: ์ธ๋ ํค๋ฅผ ํฌํจํ๋ ํ ์ด๋ธ (์: orders)
๐ SQL ์ฐธ์กฐ์ ๋ค์ํ ์ ํ๊ณผ ์ฌ์ฉ๋ฒ
1. ์ผ๋๋ค ๊ด๊ณ (One-to-Many)
๊ฐ์ฅ ์ผ๋ฐ์ ์ธ ๊ด๊ณ๋ก, ํ ๋ถ๋ชจ ๋ ์ฝ๋๊ฐ ์ฌ๋ฌ ์์ ๋ ์ฝ๋์ ์ฐ๊ฒฐ๋ฉ๋๋ค.1314
-- ๋ถ์-์ง์ ๊ด๊ณ ์์
CREATE TABLE departments (
dept_id INT PRIMARY KEY,
dept_name VARCHAR(50)
);
CREATE TABLE employees (
emp_id INT PRIMARY KEY,
emp_name VARCHAR(50),
dept_id INT,
FOREIGN KEY (dept_id) REFERENCES departments(dept_id)
);
์ค๋ฌด ํ์ฉ ์์:
-
๊ณ ๊ฐ โ ์ฃผ๋ฌธ ๊ด๊ณ
-
์นดํ ๊ณ ๋ฆฌ โ ์ ํ ๊ด๊ณ
-
๋ถ์ โ ์ง์ ๊ด๊ณ
2. ์ผ๋์ผ ๊ด๊ณ (One-to-One)
๊ฐ ๋ถ๋ชจ ๋ ์ฝ๋๊ฐ ์ ํํ ํ๋์ ์์ ๋ ์ฝ๋์ ์ฐ๊ฒฐ๋๋ ๊ด๊ณ์ ๋๋ค.15
-- ์ง์-์ฌ๊ถ ๊ด๊ณ ์์
CREATE TABLE employees (
emp_id INT PRIMARY KEY,
emp_name VARCHAR(50)
);
CREATE TABLE passports (
passport_id INT PRIMARY KEY,
emp_id INT UNIQUE NOT NULL,
passport_number VARCHAR(20),
FOREIGN KEY (emp_id) REFERENCES employees(emp_id)
);
์ฃผ์์ฌํญ: ์ผ๋์ผ ๊ด๊ณ์์๋ ์ธ๋ ํค์ UNIQUE ์ ์ฝ์กฐ๊ฑด์ ์ถ๊ฐํด์ผ ํฉ๋๋ค.15
3. ๋ค๋๋ค ๊ด๊ณ (Many-to-Many)
**์ฐ๊ฒฐ ํ ์ด๋ธ(Junction Table)**์ ํตํด ๊ตฌํ๋๋ ๋ณตํฉ ๊ด๊ณ์ ๋๋ค.1316
-- ํ์-๊ณผ๋ชฉ ๊ด๊ณ ์์
CREATE TABLE students (
student_id INT PRIMARY KEY,
student_name VARCHAR(50)
);
CREATE TABLE subjects (
subject_id INT PRIMARY KEY,
subject_name VARCHAR(50)
);
-- ์ฐ๊ฒฐ ํ
์ด๋ธ
CREATE TABLE enrollments (
student_id INT,
subject_id INT,
enrollment_date DATE,
grade CHAR(2),
PRIMARY KEY (student_id, subject_id),
FOREIGN KEY (student_id) REFERENCES students(student_id),
FOREIGN KEY (subject_id) REFERENCES subjects(subject_id)
);
4. ์๊ธฐ์ฐธ์กฐ ๊ด๊ณ (Self-Referencing)
๊ฐ์ ํ ์ด๋ธ ๋ด์์ ๋ ์ฝ๋๋ค์ด ์๋ก๋ฅผ ์ฐธ์กฐํ๋ ๊ด๊ณ์ ๋๋ค.171819
-- ์ง์-๊ด๋ฆฌ์ ๊ด๊ณ ์์
CREATE TABLE employees (
emp_id INT PRIMARY KEY,
emp_name VARCHAR(50),
manager_id INT,
FOREIGN KEY (manager_id) REFERENCES employees(emp_id)
);
ํ์ฉ ์ฌ๋ก:
-
์กฐ์ง๋์์ ์ํ๊ธ ๊ด๊ณ
-
๊ฒ์ํ์ ๋๊ธ-๋๋๊ธ ๊ตฌ์กฐ
-
์นดํ ๊ณ ๋ฆฌ์ ์์-ํ์ ๋ถ๋ฅ
โ๏ธ ์ฐธ์กฐ ๋์ ์ต์ ๊ณผ ํ์ฉ๋ฒ
SQL์์๋ ๋ถ๋ชจ ํ ์ด๋ธ์ ๋ฐ์ดํฐ๊ฐ ๋ณ๊ฒฝ๋๊ฑฐ๋ ์ญ์ ๋ ๋ ์์ ํ ์ด๋ธ์์ ์ด๋ค ๋์์ ์ํํ ์ง ์ ์ํ ์ ์์ต๋๋ค.7812
CASCADE ์ต์
๋ถ๋ชจ ๋ ์ฝ๋์ ๋ณ๊ฒฝ/์ญ์ ๊ฐ ์์ ๋ ์ฝ๋์ ์๋์ผ๋ก ์ ํ๋ฉ๋๋ค.820
CREATE TABLE orders (
order_id INT PRIMARY KEY,
customer_id INT,
order_date DATE,
FOREIGN KEY (customer_id) REFERENCES customers(customer_id)
ON DELETE CASCADE
ON UPDATE CASCADE
);
์ฅ์ :
-
๊ด๋ จ ๋ฐ์ดํฐ๊ฐ ์๋์ผ๋ก ๋๊ธฐํ๋จ
-
๊ณ ์ ๋ ์ฝ๋ ๋ฐ์ ๋ฐฉ์ง
์ฃผ์์ฌํญ:
-
์๋ํ์ง ์์ ๋๋ ์ญ์ ์ํ
-
๋ณต๊ตฌ๊ฐ ์ด๋ ค์
SET NULL ์ต์
๋ถ๋ชจ ๋ ์ฝ๋๊ฐ ์ญ์ ๋๋ฉด ์์ ํ ์ด๋ธ์ ์ธ๋ ํค ๊ฐ์ NULL๋ก ์ค์ ํฉ๋๋ค.820
CREATE TABLE orders (
order_id INT PRIMARY KEY,
customer_id INT,
order_date DATE,
FOREIGN KEY (customer_id) REFERENCES customers(customer_id)
ON DELETE SET NULL
);
ํ์ฉ ์๋๋ฆฌ์ค:
-
๋ด๋น์๊ฐ ํด์ฌํด๋ ํ๋ก์ ํธ ๊ธฐ๋ก์ ์ ์งํ๊ณ ์ถ์ ๊ฒฝ์ฐ
-
์นดํ ๊ณ ๋ฆฌ๊ฐ ์ญ์ ๋์ด๋ ์ ํ์ ๋ณด๊ดํ๊ณ ์ถ์ ๊ฒฝ์ฐ
RESTRICT/NO ACTION ์ต์
์์ ๋ ์ฝ๋๊ฐ ์กด์ฌํ๋ฉด ๋ถ๋ชจ ๋ ์ฝ๋์ ์ญ์ /์์ ์ ๊ฑฐ๋ถํฉ๋๋ค.712
CREATE TABLE orders (
order_id INT PRIMARY KEY,
customer_id INT,
order_date DATE,
FOREIGN KEY (customer_id) REFERENCES customers(customer_id)
ON DELETE RESTRICT
);
์ฅ์ :
-
์ค์๋ก ์ธํ ๋ฐ์ดํฐ ์์ค ๋ฐฉ์ง
-
๋ช ์์ ์ธ ๋ฐ์ดํฐ ์ ๋ฆฌ ๊ณผ์ ๊ฐ์
๐ง ์ค๋ฌด์์์ SQL ์ฐธ์กฐ ํ์ฉ๋ฒ
JOIN ์ฐ์ฐ๊ณผ์ ์ฐ๊ณ
์ธ๋ ํค๋ JOIN ์ฐ์ฐ์ ๊ธฐ์ด๊ฐ ๋ฉ๋๋ค.212223
-- INNER JOIN ์์
SELECT
c.customer_name,
o.order_date,
o.total_amount
FROM customers c
INNER JOIN orders o ON c.customer_id = o.customer_id
WHERE o.order_date >= '2025-01-01';
-- LEFT JOIN์ผ๋ก ๋ชจ๋ ๊ณ ๊ฐ ์กฐํ (์ฃผ๋ฌธ์ด ์๋ ๊ณ ๊ฐ ํฌํจ)
SELECT
c.customer_name,
COUNT(o.order_id) as order_count
FROM customers c
LEFT JOIN orders o ON c.customer_id = o.customer_id
GROUP BY c.customer_id, c.customer_name;
๋ณตํฉ ์ธ๋ ํค
์ฌ๋ฌ ์ปฌ๋ผ์ ์กฐํฉํ ์ธ๋ ํค๋ ๊ฐ๋ฅํฉ๋๋ค.6
CREATE TABLE order_details (
order_id INT,
product_id INT,
line_number INT,
quantity INT,
price DECIMAL(10,2),
PRIMARY KEY (order_id, line_number),
FOREIGN KEY (order_id, product_id)
REFERENCES order_products(order_id, product_id)
);
์ธ๋ฑ์ค ์ต์ ํ
์ธ๋ ํค ์ปฌ๋ผ์๋ ์๋์ผ๋ก ์ธ๋ฑ์ค๊ฐ ์์ฑ๋๋ ๊ฒฝ์ฐ๊ฐ ๋ง์ง๋ง, ์ฑ๋ฅ ์ต์ ํ๋ฅผ ์ํด ๋ช ์์ ์ผ๋ก ๊ด๋ฆฌํ๋ ๊ฒ์ด ์ข์ต๋๋ค.1224
-- ์ธ๋ ํค ์ฑ๋ฅ ์ต์ ํ๋ฅผ ์ํ ์ธ๋ฑ์ค
CREATE INDEX idx_orders_customer_id ON orders(customer_id);
CREATE INDEX idx_order_items_product_id ON order_items(product_id);
๐ ์ฐธ์กฐ์ ๋ฐ์ดํฐ๋ฒ ์ด์ค ์ ๊ทํ
SQL ์ฐธ์กฐ๋ ๋ฐ์ดํฐ๋ฒ ์ด์ค ์ ๊ทํ์ ๋ฐ์ ํ ๊ด๋ จ์ด ์์ต๋๋ค.252627
์ 1์ ๊ทํ (1NF)
๊ฐ ์ปฌ๋ผ์ด ์์๊ฐ์ ๊ฐ์ง๊ณ ๊ธฐ๋ณธ ํค๊ฐ ์กด์ฌํด์ผ ํฉ๋๋ค.2526
์๋ฐ ์ฌ๋ก:
-- ์๋ชป๋ ์์ (1NF ์๋ฐ)
CREATE TABLE orders_bad (
order_id INT,
customer_name VARCHAR(50),
product_names TEXT -- ์ฌ๋ฌ ์ ํ๋ช
์ด ํ๋์ ์ปฌ๋ผ์ ์ ์ฅ
);
์ฌ๋ฐ๋ฅธ ์์:
-- 1NF ์ค์
CREATE TABLE orders (
order_id INT PRIMARY KEY,
customer_id INT,
FOREIGN KEY (customer_id) REFERENCES customers(customer_id)
);
CREATE TABLE order_items (
order_id INT,
product_id INT,
quantity INT,
PRIMARY KEY (order_id, product_id),
FOREIGN KEY (order_id) REFERENCES orders(order_id),
FOREIGN KEY (product_id) REFERENCES products(product_id)
);
์ 2์ ๊ทํ (2NF)
๋ชจ๋ ๋นํค ์์ฑ์ด ๊ธฐ๋ณธ ํค ์ ์ฒด์ ์์ ํจ์์ ์ข ์๋์ด์ผ ํฉ๋๋ค.252627
์ 3์ ๊ทํ (3NF)
๋นํค ์์ฑ์ด ๋ค๋ฅธ ๋นํค ์์ฑ์ ์ข ์๋์ง ์์์ผ ํฉ๋๋ค.2728
๐จ ์ฐธ์กฐ ๋ช ๋ช ๊ท์น๊ณผ ๋ชจ๋ฒ ์ฌ๋ก
์ผ๊ด๋ ๋ช ๋ช ๊ท์น
๊ฐ๋ ์ฑ๊ณผ ์ ์ง๋ณด์์ฑ์ ์ํด ์ผ๊ด๋ ๋ช ๋ช ๊ท์น์ ๋ฐ๋ฅด๋ ๊ฒ์ด ์ค์ํฉ๋๋ค.24293031
-- ๊ถ์ฅ ๋ช
๋ช
๊ท์น
-- ๊ธฐ๋ณธ ํค: pk_ํ
์ด๋ธ๋ช
-- ์ธ๋ ํค: fk_ํ
์ด๋ธ๋ช
_์ฐธ์กฐํ
์ด๋ธ๋ช
-- ์ธ๋ฑ์ค: idx_ํ
์ด๋ธ๋ช
_์ปฌ๋ผ๋ช
CREATE TABLE customers (
customer_id INT,
customer_name VARCHAR(50),
email VARCHAR(100),
CONSTRAINT pk_customers PRIMARY KEY (customer_id)
);
CREATE TABLE orders (
order_id INT,
customer_id INT,
order_date DATE,
CONSTRAINT pk_orders PRIMARY KEY (order_id),
CONSTRAINT fk_orders_customers
FOREIGN KEY (customer_id) REFERENCES customers(customer_id)
);
์ ์ฝ์กฐ๊ฑด ๋ช ๋ช ๋ชจ๋ฒ ์ฌ๋ก
์ฒด๊ณ์ ์ธ ์ ์ฝ์กฐ๊ฑด ๋ช ๋ช ์ผ๋ก ๋๋ฒ๊น ๊ณผ ์ ์ง๋ณด์๋ฅผ ์ฝ๊ฒ ๋ง๋ค ์ ์์ต๋๋ค:313233
-
๊ธฐ๋ณธ ํค:
pk_ํ ์ด๋ธ๋ช
-
์ธ๋ ํค:
fk_์์ํ ์ด๋ธ_๋ถ๋ชจํ ์ด๋ธ
-
๊ณ ์ ์ ์ฝ:
uq_ํ ์ด๋ธ๋ช _์ปฌ๋ผ๋ช
-
์ฒดํฌ ์ ์ฝ:
ck_ํ ์ด๋ธ๋ช _์ปฌ๋ผ๋ช
๐จ ์ค๋ฌด์์ ์ฃผ์ํด์ผ ํ ์ฐธ์กฐ ๊ด๋ จ ์ด์๋ค
์ํ ์ฐธ์กฐ ๋ฌธ์
ํ ์ด๋ธ๋ค์ด ์๋ก๋ฅผ ์ฐธ์กฐํ๋ ์ํ ๊ตฌ์กฐ๋ ํผํด์ผ ํฉ๋๋ค.
-- ๋ฌธ์ ๊ฐ ์๋ ์ค๊ณ
CREATE TABLE employees (
emp_id INT PRIMARY KEY,
dept_id INT,
FOREIGN KEY (dept_id) REFERENCES departments(dept_id)
);
CREATE TABLE departments (
dept_id INT PRIMARY KEY,
manager_id INT,
FOREIGN KEY (manager_id) REFERENCES employees(emp_id) -- ์ํ ์ฐธ์กฐ!
);
ํด๊ฒฐ์ฑ :
-- ๊ฐ์ ๋ ์ค๊ณ
CREATE TABLE departments (
dept_id INT PRIMARY KEY,
dept_name VARCHAR(50)
);
CREATE TABLE employees (
emp_id INT PRIMARY KEY,
emp_name VARCHAR(50),
dept_id INT,
manager_id INT,
FOREIGN KEY (dept_id) REFERENCES departments(dept_id),
FOREIGN KEY (manager_id) REFERENCES employees(emp_id) -- ์๊ธฐ์ฐธ์กฐ๋ก ํด๊ฒฐ
);
์ฑ๋ฅ ๊ณ ๋ ค์ฌํญ
๋์ฉ๋ ๋ฐ์ดํฐ์์ ์ธ๋ ํค ์ ์ฝ์กฐ๊ฑด์ ์ฑ๋ฅ์ ์ํฅ์ ์ค ์ ์์ต๋๋ค:1234
-
INSERT/UPDATE ์ฑ๋ฅ: ์ฐธ์กฐ ๋ฌด๊ฒฐ์ฑ ๊ฒ์ฌ๋ก ์ธํ ์ค๋ฒํค๋
-
DELETE ์ฑ๋ฅ: CASCADE ์ต์ ์ฌ์ฉ ์ ์ฐ์ ์ญ์ ์ฒ๋ฆฌ
-
์ธ๋ฑ์ค ๊ด๋ฆฌ: ์ธ๋ ํค ์ปฌ๋ผ์ ์ ์ ํ ์ธ๋ฑ์ฑ ํ์
๋ฐ์ดํฐ ๋ง์ด๊ทธ๋ ์ด์ ์ ์ฃผ์์ฌํญ
๊ธฐ์กด ๋ฐ์ดํฐ๊ฐ ์๋ ํ ์ด๋ธ์ ์ธ๋ ํค๋ฅผ ์ถ๊ฐํ ๋๋ ์ ์คํด์ผ ํฉ๋๋ค:
-- ๊ธฐ์กด ๋ฐ์ดํฐ ์ ํฉ์ฑ ๊ฒ์ฌ ํ ์ ์ฝ์กฐ๊ฑด ์ถ๊ฐ
-- 1๋จ๊ณ: ๋ฌธ์ ๋ฐ์ดํฐ ํ์ธ
SELECT o.order_id, o.customer_id
FROM orders o
LEFT JOIN customers c ON o.customer_id = c.customer_id
WHERE c.customer_id IS NULL;
-- 2๋จ๊ณ: ๋ฌธ์ ๋ฐ์ดํฐ ์ ๋ฆฌ ํ ์ ์ฝ์กฐ๊ฑด ์ถ๊ฐ
ALTER TABLE orders
ADD CONSTRAINT fk_orders_customers
FOREIGN KEY (customer_id) REFERENCES customers(customer_id);
๐ ๊ณ ๊ธ ์ฐธ์กฐ ๊ธฐ๋ฒ๊ณผ ์ค์ ํ์ฉ
์กฐ๊ฑด๋ถ ์ฐธ์กฐ
ํน์ ์กฐ๊ฑด์ ๋ง์กฑํ๋ ๊ฒฝ์ฐ์๋ง ์ฐธ์กฐ๋ฅผ ํ์ฉํ๋ ๊ณ ๊ธ ๊ธฐ๋ฒ์ ๋๋ค.
-- ํ์ฑํ๋ ๊ณ ๊ฐ๋ง ์ฐธ์กฐ ํ์ฉํ๋ CHECK ์ ์ฝ์กฐ๊ฑด
CREATE TABLE orders (
order_id INT PRIMARY KEY,
customer_id INT,
order_date DATE,
FOREIGN KEY (customer_id) REFERENCES customers(customer_id),
CONSTRAINT ck_active_customer
CHECK (customer_id IN (
SELECT customer_id FROM customers WHERE status = 'ACTIVE'
))
);
๋ค์ค ๋ฐ์ดํฐ๋ฒ ์ด์ค ๊ฐ ์ฐธ์กฐ
์๋ก ๋ค๋ฅธ ๋ฐ์ดํฐ๋ฒ ์ด์ค ๊ฐ์ ์ฐธ์กฐ๋ ์ผ๋ฐ์ ์ผ๋ก ์ ์ฝ์กฐ๊ฑด์ผ๋ก ๊ฐ์ ํ ์ ์์ผ๋ฏ๋ก ์ ํ๋ฆฌ์ผ์ด์ ๋ ๋ฒจ์์ ๊ด๋ฆฌํด์ผ ํฉ๋๋ค.
-- ์ ํ๋ฆฌ์ผ์ด์
์์ ๊ด๋ฆฌํด์ผ ํ๋ ๊ต์ฐจ ๋ฐ์ดํฐ๋ฒ ์ด์ค ์ฐธ์กฐ
-- order_db.orders ํ
์ด๋ธ
CREATE TABLE orders (
order_id INT PRIMARY KEY,
customer_id INT, -- customer_db.customers๋ฅผ ์ฐธ์กฐํ์ง๋ง FK ์ ์ฝ์กฐ๊ฑด ๋ถ๊ฐ
order_date DATE
);
์ํํธ ์ฐธ์กฐ์ ํ๋ ์ฐธ์กฐ
์ํํธ ์ฐธ์กฐ: ์ ์ฝ์กฐ๊ฑด ์์ด ๋ ผ๋ฆฌ์ ์ผ๋ก๋ง ์ฐ๊ฒฐ
ํ๋ ์ฐธ์กฐ: ์ธ๋ ํค ์ ์ฝ์กฐ๊ฑด์ผ๋ก ๋ฌผ๋ฆฌ์ ์ฐ๊ฒฐ ๊ฐ์
-- ์ํํธ ์ฐธ์กฐ (์ ์ฐํ์ง๋ง ๋ฌด๊ฒฐ์ฑ ๋ณด์ฅ ์๋จ)
CREATE TABLE logs (
log_id INT PRIMARY KEY,
user_id INT, -- users ํ
์ด๋ธ ์ฐธ์กฐํ์ง๋ง FK ์ ์ฝ์กฐ๊ฑด ์์
action_type VARCHAR(50),
created_at TIMESTAMP
);
-- ํ๋ ์ฐธ์กฐ (๋ฌด๊ฒฐ์ฑ ๋ณด์ฅํ์ง๋ง ์ ์ฝ์ด ์์)
CREATE TABLE orders (
order_id INT PRIMARY KEY,
customer_id INT,
order_date DATE,
FOREIGN KEY (customer_id) REFERENCES customers(customer_id)
);
๐ ์ฑ๋ฅ ์ต์ ํ ์ ๋ต
์ธ๋ ํค ์ธ๋ฑ์ค ์ค๊ณ
์ธ๋ ํค ์ปฌ๋ผ์ ๋ํ ํจ์จ์ ์ธ ์ธ๋ฑ์ค ์ ๋ต์ด ์ค์ํฉ๋๋ค:1224
-- ๋ณตํฉ ์ธ๋ฑ์ค๋ก ์ฑ๋ฅ ์ต์ ํ
CREATE INDEX idx_orders_customer_date
ON orders(customer_id, order_date DESC);
-- ๋ถ๋ถ ์ธ๋ฑ์ค ํ์ฉ (PostgreSQL ์์)
CREATE INDEX idx_active_orders
ON orders(customer_id)
WHERE status = 'ACTIVE';
ํต๊ณ ์ ๋ณด ๊ด๋ฆฌ
๋ฐ์ดํฐ๋ฒ ์ด์ค ์ตํฐ๋ง์ด์ ๋ฅผ ์ํ ํต๊ณ ์ ๋ณด๋ฅผ ์ต์ ์ํ๋ก ์ ์ง:
-- SQL Server ์์
UPDATE STATISTICS customers;
UPDATE STATISTICS orders;
-- MySQL ์์
ANALYZE TABLE customers;
ANALYZE TABLE orders;
๐ ๏ธ ์ฐธ์กฐ ๋ฌด๊ฒฐ์ฑ ๊ฒ์ฆ๊ณผ ๋ชจ๋ํฐ๋ง
์ฐธ์กฐ ๋ฌด๊ฒฐ์ฑ ๊ฒ์ฌ ์ฟผ๋ฆฌ
์์คํ ์ ์ฐธ์กฐ ๋ฌด๊ฒฐ์ฑ ์ํ๋ฅผ ์ฃผ๊ธฐ์ ์ผ๋ก ์ ๊ฒํ๋ ๊ฒ์ด ์ค์ํฉ๋๋ค:
-- ๊ณ ์ ๋ ์ฝ๋ ์ฐพ๊ธฐ
SELECT 'orders' as table_name, COUNT(*) as orphan_count
FROM orders o
LEFT JOIN customers c ON o.customer_id = c.customer_id
WHERE c.customer_id IS NULL
UNION ALL
SELECT 'order_items' as table_name, COUNT(*) as orphan_count
FROM order_items oi
LEFT JOIN orders o ON oi.order_id = o.order_id
WHERE o.order_id IS NULL;
์ ์ฝ์กฐ๊ฑด ์ํ ๋ชจ๋ํฐ๋ง
-- SQL Server์์ ๋นํ์ฑํ๋ ์ ์ฝ์กฐ๊ฑด ํ์ธ
SELECT
t.name AS table_name,
fk.name AS constraint_name,
fk.is_disabled
FROM sys.foreign_keys fk
INNER JOIN sys.tables t ON fk.parent_object_id = t.object_id
WHERE fk.is_disabled = 1;
๐ ๋ฏธ๋์งํฅ์ ์ฐธ์กฐ ์ค๊ณ
๋ง์ดํฌ๋ก์๋น์ค ์ํคํ ์ฒ์์์ ์ฐธ์กฐ
๋ง์ดํฌ๋ก์๋น์ค ํ๊ฒฝ์์๋ ์๋น์ค ๊ฐ ๊ฐํ ๊ฒฐํฉ์ ํผํ๊ธฐ ์ํด ๋ค๋ฅธ ์ ๊ทผ ๋ฐฉ์์ด ํ์ํฉ๋๋ค:
-
์ด๋ฒคํธ ๊ธฐ๋ฐ ์ผ๊ด์ฑ: ๋ฐ์ดํฐ ๋ณ๊ฒฝ์ ์ด๋ฒคํธ๋ก ์ ํ
-
Saga ํจํด: ๋ถ์ฐ ํธ๋์ญ์ ๊ด๋ฆฌ
-
์ต์ข ์ผ๊ด์ฑ: ๊ฐํ ์ผ๊ด์ฑ ๋์ ์ต์ข ์ ์ผ๊ด์ฑ ์์ฉ
ํด๋ผ์ฐ๋ ํ๊ฒฝ์์์ ๊ณ ๋ ค์ฌํญ
ํด๋ผ์ฐ๋ ๋ฐ์ดํฐ๋ฒ ์ด์ค์์๋ ์ถ๊ฐ์ ์ธ ๊ณ ๋ ค์ฌํญ์ด ์์ต๋๋ค:
-
๋ฆฌ์ ๊ฐ ๋ณต์ : ์ธ๋ ํค ์ ์ฝ์กฐ๊ฑด๊ณผ ๋ณต์ ์ ์ฑ ์ ์ถฉ๋
-
์๋ ์ค์ผ์ผ๋ง: ์ฐธ์กฐ ๋ฌด๊ฒฐ์ฑ ๊ฒ์ฌ์ ์ฑ๋ฅ ์ํฅ
-
๋ฐฑ์ /๋ณต๊ตฌ: ๊ด๋ จ ํ ์ด๋ธ์ ์ผ๊ด๋ ๋ฐฑ์ ๋ณด์ฅ
๐ฏ ๊ฒฐ๋ก ๋ฐ ํต์ฌ ํฌ์ธํธ
SQL์์ ์ฐธ์กฐ๋ ๋จ์ํ ํ ์ด๋ธ์ ์ฐ๊ฒฐํ๋ ๊ธฐ์ ์ด ์๋, ๋ฐ์ดํฐ์ ํ์ง๊ณผ ์ ๋ขฐ์ฑ์ ๋ณด์ฅํ๋ ํต์ฌ ๋ฉ์ปค๋์ฆ์ ๋๋ค. ํ๋์ ๋ณต์กํ ์ ํ๋ฆฌ์ผ์ด์ ์์ ๋ฐ์ดํฐ ๋ฌด๊ฒฐ์ฑ์ ์ ์งํ๋ ค๋ฉด ์ฐธ์กฐ ์ค๊ณ์ ๋ํ ๊น์ ์ดํด๊ฐ ํ์์ ์ ๋๋ค.
ํต์ฌ ๊ธฐ์ต์ฌํญ:
-
์ฐธ์กฐ๋ ๋ฐ์ดํฐ ๋ฌด๊ฒฐ์ฑ์ ๊ธฐ์ด - ์ธ๋ ํค ์ ์ฝ์กฐ๊ฑด์ ํตํด ๋ ผ๋ฆฌ์ ์ผ๋ก ๋ถ๊ฐ๋ฅํ ๋ฐ์ดํฐ ์์ฑ์ ๋ฐฉ์ง
-
๊ด๊ณ ์ ํ์ ์ ํํ ํ์ - ์ผ๋๋ค, ์ผ๋์ผ, ๋ค๋๋ค, ์๊ธฐ์ฐธ์กฐ ๊ด๊ณ์ ํน์ฑ์ ์ดํดํ๊ณ ์ ์ ํ ๊ตฌํ
-
์ฐธ์กฐ ๋์ ์ต์ ์ ์ ์คํ ์ ํ - CASCADE, SET NULL, RESTRICT ๋ฑ์ ์ต์ ์ด ๋น์ฆ๋์ค ์๊ตฌ์ฌํญ์ ๋ง๋์ง ๊ฒํ
-
์ฑ๋ฅ๊ณผ ๋ฌด๊ฒฐ์ฑ์ ๊ท ํ - ์ฐธ์กฐ ๋ฌด๊ฒฐ์ฑ ๋ณด์ฅ๊ณผ ์ฑ๋ฅ ์ต์ ํ ์ฌ์ด์ ์ ์ ํ ๊ท ํ์ ์ฐพ๊ธฐ
-
์ผ๊ด๋ ๋ช ๋ช ๊ท์น - ํ ํ์ ๊ณผ ์ ์ง๋ณด์์ฑ์ ์ํ ์ฒด๊ณ์ ์ธ ๋ค์ด๋ฐ ์ปจ๋ฒค์ ์ ์ฉ
SQL ์ฐธ์กฐ๋ฅผ ๋ง์คํฐํ๋ ๊ฒ์ ๊ฒฌ๊ณ ํ๊ณ ํ์ฅ ๊ฐ๋ฅํ ๋ฐ์ดํฐ๋ฒ ์ด์ค ์ค๊ณ์ ์ถ๋ฐ์ ์ ๋๋ค. ์ด ํธ๋๋ถ์ ๋ด์ฉ์ ๋ฐํ์ผ๋ก ์ค๋ฌด์์ ๋ง๋๋ ๋ค์ํ ๋ฐ์ดํฐ ๊ด๊ณ๋ฅผ ํจ๊ณผ์ ์ผ๋ก ์ค๊ณํ๊ณ ๊ด๋ฆฌํ ์ ์์ ๊ฒ์ ๋๋ค. ๋ฐ์ดํฐ์ ๋ฌด๊ฒฐ์ฑ์ ๊ณง ๋น์ฆ๋์ค์ ์ ๋ขฐ์ฑ์ด๋ฉฐ, SQL ์ฐธ์กฐ๋ ๊ทธ ์ ๋ขฐ์ฑ์ ๊ธฐ์ ์ ์ผ๋ก ๋ท๋ฐ์นจํ๋ ํต์ฌ ๋๊ตฌ์์ ๊ธฐ์ตํ์๊ธฐ ๋ฐ๋๋๋ค.
๋ ํผ๋ฐ์ค(References)
Footnotes
-
https://learn.microsoft.com/en-us/sql/relational-databases/tables/create-foreign-key-relationships?view=sql-server-ver17 โฉ
-
https://www.w3schools.com/sql/sql_foreignkey.asp โฉ โฉ2 โฉ3
-
https://stackoverflow.com/questions/41906587/database-design-without-relations-with-relations-should-i-use-foreign-keys โฉ โฉ2
-
https://cloud.google.com/spanner/docs/foreign-keys/how-to โฉ โฉ2
-
https://www.ibm.com/docs/en/i/7.5.0?topic=constraints-referential โฉ โฉ2
-
https://www.slainstitute.com/primary-key-and-foreign-in-sql/ โฉ โฉ2 โฉ3
-
https://milvus.io/ai-quick-reference/how-do-foreign-keys-work-in-sql โฉ โฉ2 โฉ3 โฉ4
-
https://www.acceldata.io/blog/why-referential-integrity-constraints-are-vital-for-data-accuracy โฉ
-
https://docs.oracle.com/cd/E05553_01/books/admintool/admintool_DataModeling4.html โฉ
-
https://dev.mysql.com/doc/en/create-table-foreign-keys.html โฉ
-
https://opentextbc.ca/dbdesign01/chapter/chapter-9-integrity-rules-and-constraints/ โฉ โฉ2 โฉ3 โฉ4 โฉ5 โฉ6
-
https://dev.to/bshadmehr/mastering-table-relationships-in-relational-databases-the-role-of-primary-and-foreign-keys-1go9 โฉ โฉ2
-
https://www.cockroachlabs.com/blog/what-is-a-foreign-key/ โฉ
-
https://www.ibm.com/docs/en/db2/11.5.x?topic=constraints-foreign-key-referential โฉ โฉ2
-
https://stackoverflow.com/questions/23771547/database-design-foreign-key-and-primary-key-relationships-across-3-tables โฉ
-
https://strapi.io/blog/5-key-sql-relationship-types-to-improve-database-design โฉ
-
https://learn.microsoft.com/en-us/sql/relational-databases/tables/primary-and-foreign-key-constraints?view=sql-server-ver17 โฉ
-
https://www.reddit.com/r/SQL/comments/17bq4p2/primary_key_vs_foreign_key/ โฉ
-
https://public.support.unisys.com/aseries/docs/ClearPath-MCP-20.0/82223819-004/section-000018865.html โฉ โฉ2
-
https://www.geeksforgeeks.org/sql/relationships-in-sql-one-to-one-one-to-many-many-to-many/ โฉ
-
https://www.reddit.com/r/SQL/comments/1e14nqr/many_to_many_one_to_many_many_to_one/ โฉ
-
https://stackoverflow.com/questions/4601703/difference-between-one-to-many-and-many-to-one-relationship โฉ
-
https://www.devart.com/dbforge/sql/studio/sql-relationships.html โฉ โฉ2 โฉ3
-
https://www.metabase.com/learn/grow-your-data-skills/data-fundamentals/table-relationships โฉ โฉ2 โฉ3
-
https://stackoverflow.com/questions/25878192/how-to-add-a-foreign-key-referring-to-itself-in-sql-server-2008 โฉ โฉ2 โฉ3
-
https://www.geeksforgeeks.org/dbms/difference-between-on-delete-cascade-and-on-delete-set-null-in-dbms/ โฉ โฉ2 โฉ3
-
https://codefinity.com/courses/v2/5ac24d9d-4a16-45b3-8856-07dec028c5e9/3d6c4ab0-f470-4b5d-ad0e-5f76d28ca0af/7992cacf-81b2-4169-b8e9-6d2e322daf07 โฉ
-
https://www.dbvis.com/thetable/how-to-use-a-foreign-key-referring-to-the-source-table-in-postgres/ โฉ
-
https://support.microsoft.com/en-us/office/guide-to-table-relationships-30446197-4fbe-457b-b992-2f6fb812b58f โฉ
-
https://database.guide/understanding-self-referencing-foreign-keys-a-beginners-tutorial/ โฉ โฉ2
-
https://stackoverflow.com/questions/5383612/setting-up-table-relations-what-do-cascade-set-null-and-restrict-do โฉ
-
https://voiceofthedba.com/2023/11/06/creating-a-self-referencing-fk-in-a-create-statement-sqlnewblogger/ โฉ
-
https://www.geeksforgeeks.org/sql/cascading-referential-integrity-constraints-in-sql-server-management-studio/ โฉ