현재 오즈코딩스쿨 강의를 통해 프론트엔드를 학습하고 있습니다.
본 포스트는 해당 강의에 대한 내용 정리를 목적으로 합니다.
데이터 모델링은 현실 세계의 데이터를 구조화하여, 데이터베이스에 저장하고 효율적으로 사용할 수 있도록 설계하는 과정이다.
| 단계 | 설명 | 사용 모델 |
|---|---|---|
| 개념적 모델링 | 업무 중심의 데이터 구조를 설계하는 단계이다. | ERD (Entity Relationship Diagram) |
| 논리적 모델링 | DBMS에 독립적인 논리적 구조를 설계하는 단계이다. | 정규화된 테이블 구조 |
| 물리적 모델링 | 실제 데이터베이스 시스템에 맞게 설계하는 단계이다. | SQL DDL (CREATE TABLE 등) |
| 용어 | 설명 |
|---|---|
| 엔티티(Entity) | 독립적으로 존재하며 관리할 대상이 되는 객체이다. (예: 사용자, 상품, 주문 등) |
| 속성(Attribute) | 엔티티가 가지는 고유한 정보이다. (예: 이름, 이메일, 가격 등) |
| 관계(Relationship) | 두 개 이상의 엔티티 간의 연관성을 나타내는 요소이다. |
| 기본키(Primary Key) | 엔티티를 유일하게 식별할 수 있는 속성이다. |
| 외래키(Foreign Key) | 다른 테이블의 기본키를 참조하여 관계를 표현하는 속성이다. |
ERDCloud: 웹 기반 ERD 작성 도구이다.
- ERD 예시
[User] --------< [Order]
| |
user_id (PK) order_id (PK)
name user_id (FK)
email date
User 엔티티와 Order 엔티티는 1:N 관계이다.
하나의 사용자는 여러 개의 주문을 할 수 있는 구조이다.
dbdiagram.io: 간단하고 직관적인 모델링 도구이다.
MySQL Workbench: MySQL에서 공식 제공하는 ERD 설계 도구이다.
Oracle SQL Developer: 오라클 전용 데이터 모델링 및 관리 도구이다.



정규화는 데이터의 중복을 줄이고, 데이터 무결성을 높이기 위해 테이블을 구조적으로 나누는 과정이다.

🔁 데이터 중복 감소
🛡️ 데이터 무결성 향상
📚 데이터 구조의 명확화
📈 확장성과 유연성 향상
🧮 정확한 질의(Query) 결과
🔒 보안 관리 용이
조인이 많아져 복잡한 쿼리 발생 가능
실시간 성능이 중요한 시스템에서는 비정규화로 속도 최적화 필요
그래서 일반적으로 3차 정규형(3NF)까지 정규화하고, 읽기 성능이 중요한 상황에서는 일부 비정규화(denormalization)도 사용한다.


제1정규형(1NF)은 데이터베이스 정규화의 첫 번째 단계로, 가장 기본적이고 중요한 정규화 규칙이다.
모든 컬럼의 값은 원자값(atomic value)을 가져야 한다. 즉, 하나의 칸(셀)에는 하나의 값만 존재해야 한다.






| 항목 | 설명 |
|---|---|
| 원자성(Atomicity) | 각 칼럼은 더 이상 나눌 수 없는 단일 값만 가져야 함 |
| 반복 그룹 제거 | 배열, 리스트, 쉼표 구분 값 등 중복 구조 제거 |
✅ Primary Key


| 특징 | 설명 |
|---|---|
| 고유성 | 각 행을 유일하게 식별할 수 있어야 한다. |
| NOT NULL | 기본 키는 절대 NULL을 가질 수 없다. |
| 단일 또는 복합 | 하나의 컬럼 또는 여러 컬럼의 조합으로 구성 가능하다. |
| 테이블당 1개만 가능 | 하나의 테이블에는 오직 하나의 Primary Key만 설정할 수 있다. |

2NF = 1NF + 기본키에 대한 부분 함수 종속 제거
함수 종속(Function Dependency)이란?
부분 함수 종속(Partial Dependency)이란?
제3정규형(3NF)이란, 제2정규형(2NF)을 만족하면서 이행적 함수 종속(Transitive Dependency)이 없는 상태를 의미한다.
즉, 기본키가 아닌 속성이 다른 기본키가 아닌 속성에 종속되지 않아야 한다는 것이 핵심이다.



order 테이블의 customer_id는 customer 테이블의 customer_id를 참조한다.





CREATE TABLE user (
user_id SERIAL PRIMARY KEY,
name VARCHAR(50)
);
CREATE TABLE profile (
user_id INT PRIMARY KEY,
bio TEXT,
FOREIGN KEY (user_id) REFERENCES user(user_id)
);




CREATE TABLE customer (
customer_id SERIAL PRIMARY KEY,
name VARCHAR(50)
);
CREATE TABLE orders (
order_id SERIAL PRIMARY KEY,
order_date DATE,
customer_id INT,
FOREIGN KEY (customer_id) REFERENCES customer(customer_id)
);
customer_id는 orders 테이블에 Foreign Key로 사용됨







CREATE TABLE student (
student_id SERIAL PRIMARY KEY,
name VARCHAR(50)
);
CREATE TABLE course (
course_id SERIAL PRIMARY KEY,
title VARCHAR(100)
);
-- 중간 테이블 필요
CREATE TABLE enrollment (
student_id INT,
course_id INT,
PRIMARY KEY (student_id, course_id),
FOREIGN KEY (student_id) REFERENCES student(student_id),
FOREIGN KEY (course_id) REFERENCES course(course_id)
);
enrollment이 학생-과목 관계를 연결하는 중간 테이블다른 테이블의 기본 키를 참조하여 관계를 형성
데이터 무결성 보장, JOIN 가능

조인은 두 개 이상의 테이블을 특정 조건에 따라 연결하여 하나의 결과로 보여주는 SQL 문법이다.







두 테이블에서 조건에 맞는 행만 출력하는 방식이다.
SELECT u.name, o.order_date
FROM users u
INNER JOIN orders o ON u.user_id = o.user_id;
users와 orders 테이블을 user_id로 연결하여 주문한 사용자만 보여주는 쿼리이다.

왼쪽 테이블은 모두 출력하고, 오른쪽 테이블은 일치하는 데이터만 출력한다. (없으면 NULL)
SELECT u.name, o.order_date
FROM users u
LEFT JOIN orders o ON u.user_id = o.user_id;


오른쪽 테이블은 모두 출력하고, 왼쪽 테이블은 일치하는 데이터만 출력한다. (MySQL 등에서 사용)
SELECT u.name, o.order_date
FROM users u
RIGHT JOIN orders o ON u.user_id = o.user_id;




SELECT a.id, a.name, b.score
FROM student a
FULL JOIN grade b ON a.id = b.id;



SELECT color_name, size_name
FROM color
CROSS JOIN size;





SELECT
e.name AS employee,
m.name AS manager
FROM
employee e
LEFT JOIN
employee m ON e.manager_id = m.emp_id;

GROUP BY는 SQL에서 데이터를 특정 기준으로 묶어 집계 함수(Aggregate Function)를 적용할 때 사용하는 구문이다.
SELECT 열1, 집계함수(열2)
FROM 테이블
GROUP BY 열1;
열1 기준으로 데이터를 묶고, 묶인 그룹마다 열2에 집계함수를 적용하는 구조이다.
자주 쓰는 집계 함수
| 함수 | 설명 |
| ---------- | --------- |
| COUNT(*) | 행의 개수를 센다 |
| SUM(열) | 합계를 구한다 |
| AVG(열) | 평균을 구한다 |
| MAX(열) | 최대값을 구한다 |
| MIN(열) | 최소값을 구한다 |
WHERE는 집계되기 전 조건 필터링, HAVING은 집계된 결과를 나중에 필터링할 때 사용한다.
SELECT user_id, SUM(total_amt) AS total_spent
FROM orders
GROUP BY user_id
HAVING SUM(total_amt) > 20000;
여러 기준으로 묶고 싶을 때는 쉼표로 열을 나열한다.
SELECT user_id, DATE(order_date), COUNT(*) AS daily_orders
FROM orders
GROUP BY user_id, DATE(order_date);
| 항목 | 설명 |
|---|---|
GROUP BY | 데이터를 기준 컬럼으로 묶는다 |
집계 함수 | 묶인 그룹에 통계 처리를 적용한다 |
HAVING | 그룹화된 결과에 조건을 건다 |
GROUP BY 다중 열 | 복합 기준으로 그룹화한다 |
쿼리 안에 또 다른 쿼리를 넣어 결과를 조건으로 사용하는 방식이다.
SELECT name
FROM users
WHERE user_id IN (
SELECT user_id
FROM orders
WHERE order_date >= '2025-01-01'
);
두 개 이상의 SELECT 결과를 위로 이어 붙이는 방식이다. (열 개수와 데이터 타입이 같아야 한다.)
SELECT name, email FROM customers
UNION
SELECT name, email FROM suppliers;
UNION ALL을 사용한다.여러 테이블을 대상으로 데이터를 삽입, 수정, 삭제할 수도 있다. 하지만 일반적으로는 트랜잭션을 사용하여 하나의 논리적 작업으로 묶는 방식을 많이 쓴다.
START TRANSACTION;
INSERT INTO orders (user_id, order_date) VALUES (1, NOW());
INSERT INTO order_items (order_id, product_id, quantity) VALUES (LAST_INSERT_ID(), 101, 2);
COMMIT;
Pagila 데이터베이스는 PostgreSQL 전용 샘플 데이터베이스로, MySQL의 유명 샘플 DB인 Sakila를 기반으로 만들어졌다.
영화 대여점을 주제로 하며, 현실적인 비즈니스 시나리오를 반영한 데이터 구조를 제공한다. SQL 학습, 조인 연습, 통계 분석, 데이터 모델링 등에 유용하다.
| 테이블명 | 설명 |
|---|---|
film | 영화 기본 정보 (제목, 길이, 등급 등) |
actor | 배우 정보 |
film_actor | 영화-배우 관계 (N\:M) |
category | 영화 장르 |
film_category | 영화-장르 관계 |
language | 영화 언어 |
customer | 고객 정보 |
address, city, country | 주소 정보 |
store | 지점 (매장) 정보 |
staff | 매장 직원 정보 |
inventory | 매장 내 보유 DVD 재고 정보 |
rental | 대여 기록 |
payment | 결제 기록 |
[film] ---< [film_actor] >--- [actor]
|
v
[film_category] >--- [category]
|
v
[inventory] ---< [rental] ---< [payment]
^
[customer]
# postgresql 설치
brew install postgresql@16
# 설정 파일 수정
vi ~/.zshrc
# 수정한 설정 파일 적용
source ~/.zshrc
#postgresql로 주석처리 된 부분을 확인해보면 zshrc 파일을 열어서 postgresql 경로를 등록
# postgresql 실행
brew services start postgresql@16
# 상태 확인
brew services list
CREATE DATABASE pagila;
psql -U postgres -d pagila -f pagila-schema.sql
psql -U postgres -d pagila -f pagila-data.sql
postgres는 PostgreSQL의 기본 사용자명이고, pagila는 사용할 데이터베이스 이름이다.
pagila-schema.sql은 테이블 정의, pagila-data.sql은 초기 데이터가 들어 있는 파일이다.
방법 2: pgAdmin 사용
GUI를 선호한다면 pgAdmin으로도 쉽게 설정할 수 있다.
pgAdmin에서 pagila 데이터베이스를 선택하고 Query Tool에서 SQL 파일을 실행하면 된다.
SELECT * FROM actor LIMIT 10;
SELECT * FROM film LIMIT 10;
Pagila는 아래와 같은 주요 주체(Entity)로 구성되어 있다