[Python 100일 챌린지] Day 73 - SQL 기본 (CREATE, INSERT)
데이터베이스의 시작은 테이블 만들기부터! SQL의 CREATE와 INSERT는 데이터베이스 작업의 가장 기본이에요. 테이블 구조를 설계하고 데이터를 추가하는 방법을 배우면, 여러분만의 데이터베이스를 만들고 관리할 수 있습니다. 오늘은 Python의 sqlite3로 실제 데이터베이스를 만들어보며 SQL의 기초를 다져봅시다! 😊
(25분 완독 ⭐⭐)
🎯 오늘의 학습 목표
📚 사전 지식
- Day 72: SQLite 시작하기 - SQLite 연결 및 기본 사용법
🎯 학습 목표 1: CREATE TABLE로 테이블 만들기
한 줄 설명
CREATE TABLE = 데이터를 저장할 표 만들기
엑셀의 시트처럼 행(row)과 열(column)로 구성된 테이블을 생성합니다.
기본 문법
1
2
3
4
5
CREATE TABLE 테이블명 (
컬럼명1 데이터타입,
컬럼명2 데이터타입,
컬럼명3 데이터타입
);
첫 번째 테이블 만들기
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
import sqlite3
# 데이터베이스 연결
conn = sqlite3.connect('mydb.db')
cursor = conn.cursor()
# 학생 테이블 생성
cursor.execute('''
CREATE TABLE students (
id INTEGER,
name TEXT,
age INTEGER,
grade TEXT
)
''')
conn.commit()
conn.close()
print("테이블 생성 완료!")
테이블 구조:
1
2
3
4
5
6
students 테이블
┌────┬──────┬─────┬───────┐
│ id │ name │ age │ grade │
├────┼──────┼─────┼───────┤
│ │ │ │ │ ← 데이터가 들어갈 공간
└────┴──────┴─────┴───────┘
테이블 존재 여부 확인
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
import sqlite3
conn = sqlite3.connect('mydb.db')
cursor = conn.cursor()
# 테이블이 없을 때만 생성
cursor.execute('''
CREATE TABLE IF NOT EXISTS students (
id INTEGER,
name TEXT,
age INTEGER,
grade TEXT
)
''')
conn.commit()
conn.close()
💡
IF NOT EXISTS를 사용하면 이미 테이블이 있을 때 에러가 발생하지 않습니다!
🎯 학습 목표 2: SQL 데이터 타입 이해하기
SQLite의 주요 데이터 타입
SQLite는 5가지 주요 데이터 타입을 지원합니다:
1. INTEGER (정수)
1
2
3
4
5
CREATE TABLE users (
id INTEGER, # 1, 2, 3, 100, -50
age INTEGER,
score INTEGER
)
용도: 나이, 점수, 개수, ID 등
2. TEXT (문자열)
1
2
3
4
5
CREATE TABLE users (
name TEXT, # "홍길동", "Kim"
email TEXT, # "[email protected]"
address TEXT
)
용도: 이름, 이메일, 주소, 설명 등
3. REAL (실수)
1
2
3
4
5
CREATE TABLE products (
price REAL, # 19.99, 3.14
weight REAL, # 1.5, 0.25
rating REAL # 4.5
)
용도: 가격, 무게, 평점, 온도 등
4. BLOB (바이너리 데이터)
1
2
3
CREATE TABLE files (
file_data BLOB # 이미지, 파일 등
)
용도: 이미지, 오디오, 파일 등 바이너리 데이터
5. NULL (값 없음)
1
2
# 값이 없는 상태
age = NULL # 나이 정보 없음
실전 예제: 다양한 타입 사용
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
import sqlite3
conn = sqlite3.connect('shop.db')
cursor = conn.cursor()
cursor.execute('''
CREATE TABLE IF NOT EXISTS products (
id INTEGER,
name TEXT,
price REAL,
stock INTEGER,
description TEXT,
image BLOB
)
''')
conn.commit()
conn.close()
print("상품 테이블 생성 완료!")
🎯 학습 목표 3: 제약조건으로 데이터 품질 보장하기
PRIMARY KEY (기본 키)
역할: 각 행을 고유하게 식별하는 컬럼
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
import sqlite3
conn = sqlite3.connect('mydb.db')
cursor = conn.cursor()
cursor.execute('''
CREATE TABLE students (
id INTEGER PRIMARY KEY, # 중복 불가, NULL 불가
name TEXT,
age INTEGER
)
''')
conn.commit()
conn.close()
특징:
- 중복된 값 불가
- NULL 값 불가
- 자동으로 인덱스 생성 (검색 빠름)
AUTOINCREMENT (자동 증가)
1
2
3
4
5
6
7
cursor.execute('''
CREATE TABLE students (
id INTEGER PRIMARY KEY AUTOINCREMENT, # 1, 2, 3... 자동 증가
name TEXT,
age INTEGER
)
''')
장점:
- ID를 직접 지정하지 않아도 자동으로 1씩 증가
- 삭제된 ID 재사용 안 함
NOT NULL (필수 값)
1
2
3
4
5
6
7
8
cursor.execute('''
CREATE TABLE students (
id INTEGER PRIMARY KEY AUTOINCREMENT,
name TEXT NOT NULL, # 이름 필수
age INTEGER NOT NULL, # 나이 필수
phone TEXT # 선택 (NULL 가능)
)
''')
DEFAULT (기본값)
1
2
3
4
5
6
7
8
9
cursor.execute('''
CREATE TABLE posts (
id INTEGER PRIMARY KEY AUTOINCREMENT,
title TEXT NOT NULL,
content TEXT,
views INTEGER DEFAULT 0, # 기본값 0
created_at TEXT DEFAULT CURRENT_TIMESTAMP # 현재 시간
)
''')
UNIQUE (고유값)
1
2
3
4
5
6
7
8
cursor.execute('''
CREATE TABLE users (
id INTEGER PRIMARY KEY AUTOINCREMENT,
username TEXT UNIQUE, # 중복 불가
email TEXT UNIQUE, # 중복 불가
name TEXT
)
''')
종합 예제: 모든 제약조건 활용
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
import sqlite3
conn = sqlite3.connect('company.db')
cursor = conn.cursor()
cursor.execute('''
CREATE TABLE IF NOT EXISTS employees (
id INTEGER PRIMARY KEY AUTOINCREMENT,
employee_id TEXT UNIQUE NOT NULL,
name TEXT NOT NULL,
email TEXT UNIQUE NOT NULL,
department TEXT NOT NULL,
salary REAL DEFAULT 0,
hire_date TEXT DEFAULT CURRENT_TIMESTAMP,
is_active INTEGER DEFAULT 1
)
''')
conn.commit()
conn.close()
print("직원 테이블 생성 완료!")
🎯 학습 목표 4: INSERT로 데이터 추가하기
기본 INSERT 문법
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
import sqlite3
conn = sqlite3.connect('mydb.db')
cursor = conn.cursor()
# 단일 행 삽입
cursor.execute('''
INSERT INTO students (id, name, age, grade)
VALUES (1, '홍길동', 20, 'A')
''')
conn.commit()
conn.close()
print("데이터 추가 완료!")
컬럼 순서와 값 순서 일치
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# 방법 1: 모든 컬럼 명시
cursor.execute('''
INSERT INTO students (id, name, age, grade)
VALUES (2, '김철수', 22, 'B')
''')
# 방법 2: 일부 컬럼만 (나머지는 NULL 또는 DEFAULT)
cursor.execute('''
INSERT INTO students (name, age)
VALUES ('이영희', 21)
''')
# 방법 3: 모든 컬럼 순서대로 (컬럼명 생략)
cursor.execute('''
INSERT INTO students
VALUES (3, '박민수', 23, 'A')
''')
여러 행 한 번에 삽입
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
import sqlite3
conn = sqlite3.connect('mydb.db')
cursor = conn.cursor()
# 여러 데이터 준비
students_data = [
(4, '정수진', 20, 'A'),
(5, '최동욱', 22, 'B'),
(6, '강지혜', 21, 'A'),
(7, '윤서연', 23, 'C')
]
# executemany로 한 번에 삽입
cursor.executemany('''
INSERT INTO students (id, name, age, grade)
VALUES (?, ?, ?, ?)
''', students_data)
conn.commit()
print(f"{len(students_data)}개 데이터 추가 완료!")
conn.close()
출력:
1
4개 데이터 추가 완료!
Python 변수 사용하여 삽입
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
import sqlite3
conn = sqlite3.connect('mydb.db')
cursor = conn.cursor()
# 변수로 데이터 준비
name = "안유진"
age = 24
grade = "A"
# ? 플레이스홀더 사용 (SQL Injection 방지)
cursor.execute('''
INSERT INTO students (name, age, grade)
VALUES (?, ?, ?)
''', (name, age, grade))
conn.commit()
conn.close()
print(f"{name} 학생 정보 추가 완료!")
⚠️ 보안 주의: 항상
?플레이스홀더를 사용하세요! 문자열 포맷팅(f-string,%)은 SQL Injection 공격에 취약합니다.
실전 예제: 상품 데이터 추가
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
import sqlite3
conn = sqlite3.connect('shop.db')
cursor = conn.cursor()
# 테이블 생성
cursor.execute('''
CREATE TABLE IF NOT EXISTS products (
id INTEGER PRIMARY KEY AUTOINCREMENT,
name TEXT NOT NULL,
price REAL NOT NULL,
stock INTEGER DEFAULT 0,
category TEXT
)
''')
# 상품 데이터
products = [
('노트북', 1200000, 15, '전자제품'),
('마우스', 35000, 50, '전자제품'),
('키보드', 89000, 30, '전자제품'),
('모니터', 250000, 20, '전자제품'),
('의자', 150000, 10, '가구')
]
# 데이터 삽입
cursor.executemany('''
INSERT INTO products (name, price, stock, category)
VALUES (?, ?, ?, ?)
''', products)
conn.commit()
print(f"{len(products)}개 상품 추가 완료!")
# 확인
cursor.execute('SELECT * FROM products')
rows = cursor.fetchall()
print("\n등록된 상품 목록:")
for row in rows:
print(f"ID: {row[0]}, 상품명: {row[1]}, 가격: {row[2]:,}원, 재고: {row[3]}개")
conn.close()
출력:
1
2
3
4
5
6
7
8
5개 상품 추가 완료!
등록된 상품 목록:
ID: 1, 상품명: 노트북, 가격: 1,200,000원, 재고: 15개
ID: 2, 상품명: 마우스, 가격: 35,000원, 재고: 50개
ID: 3, 상품명: 키보드, 가격: 89,000원, 재고: 30개
ID: 4, 상품명: 모니터, 가격: 250,000원, 재고: 20개
ID: 5, 상품명: 의자, 가격: 150,000원, 재고: 10개
💡 실전 팁 & 주의사항
💡 Tip 1: 테이블 설계는 신중하게
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
# ❌ 나쁜 예 - 컬럼이 너무 많음
CREATE TABLE users (
id, name, age, email, phone, address, city, country,
zipcode, job, company, department, salary, ...
)
# ✅ 좋은 예 - 테이블 분리
CREATE TABLE users (
id, name, email, phone
)
CREATE TABLE user_profiles (
user_id, address, city, country, zipcode
)
CREATE TABLE user_employment (
user_id, job, company, department, salary
)
💡 Tip 2: PRIMARY KEY는 항상 설정
1
2
3
4
5
6
7
8
9
10
11
12
# ❌ PRIMARY KEY 없음
CREATE TABLE users (
name TEXT,
email TEXT
) # 중복 데이터 구분 불가!
# ✅ PRIMARY KEY 설정
CREATE TABLE users (
id INTEGER PRIMARY KEY AUTOINCREMENT,
name TEXT,
email TEXT
)
💡 Tip 3: 필수 데이터는 NOT NULL
1
2
3
4
5
6
7
8
9
10
11
12
13
14
# ❌ 필수 정보가 NULL 가능
CREATE TABLE orders (
id INTEGER PRIMARY KEY,
product_name TEXT, # NULL 가능
customer_email TEXT # NULL 가능
)
# ✅ 필수 정보는 NOT NULL
CREATE TABLE orders (
id INTEGER PRIMARY KEY AUTOINCREMENT,
product_name TEXT NOT NULL,
customer_email TEXT NOT NULL,
delivery_address TEXT # 선택 사항
)
💡 Tip 4: commit() 잊지 않기
1
2
3
4
5
6
7
8
# ❌ commit() 없음 - 데이터 저장 안 됨!
cursor.execute('INSERT INTO users VALUES (1, "홍길동")')
conn.close()
# ✅ commit() 필수!
cursor.execute('INSERT INTO users VALUES (1, "홍길동")')
conn.commit() # 반드시 커밋!
conn.close()
🧪 연습 문제
문제 1: 도서 관리 시스템 테이블 생성
과제: 도서관의 책 정보를 관리할 테이블을 만들고 데이터를 추가하세요.
요구사항:
books테이블 생성- id: 자동 증가 기본 키
- title: 책 제목 (필수)
- author: 저자 (필수)
- isbn: ISBN (고유값, 필수)
- price: 가격 (실수형)
- stock: 재고 (기본값 0)
- published_date: 출판일
- 다음 도서 데이터 추가:
- (“파이썬 정복”, “홍길동”, “979-11-1234-567-8”, 25000, 10, “2024-01-15”)
- (“데이터베이스 기초”, “김철수”, “979-11-1234-568-5”, 30000, 5, “2024-02-20”)
- (“웹 개발 완벽 가이드”, “이영희”, “979-11-1234-569-2”, 35000, 8, “2024-03-10”)
- 전체 도서 목록 출력
💡 힌트
PRIMARY KEY AUTOINCREMENT로 id 자동 생성NOT NULL로 필수 컬럼 지정UNIQUE로 ISBN 중복 방지DEFAULT로 재고 기본값 설정executemany()로 여러 행 한 번에 삽입
✅ 정답
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
import sqlite3
# 데이터베이스 연결
conn = sqlite3.connect('library.db')
cursor = conn.cursor()
# 1. 테이블 생성
cursor.execute('''
CREATE TABLE IF NOT EXISTS books (
id INTEGER PRIMARY KEY AUTOINCREMENT,
title TEXT NOT NULL,
author TEXT NOT NULL,
isbn TEXT UNIQUE NOT NULL,
price REAL,
stock INTEGER DEFAULT 0,
published_date TEXT
)
''')
print("도서 테이블 생성 완료!")
# 2. 도서 데이터 추가
books_data = [
("파이썬 정복", "홍길동", "979-11-1234-567-8", 25000, 10, "2024-01-15"),
("데이터베이스 기초", "김철수", "979-11-1234-568-5", 30000, 5, "2024-02-20"),
("웹 개발 완벽 가이드", "이영희", "979-11-1234-569-2", 35000, 8, "2024-03-10")
]
cursor.executemany('''
INSERT INTO books (title, author, isbn, price, stock, published_date)
VALUES (?, ?, ?, ?, ?, ?)
''', books_data)
conn.commit()
print(f"\n{len(books_data)}권의 도서 추가 완료!")
# 3. 전체 도서 목록 출력
cursor.execute('SELECT * FROM books')
books = cursor.fetchall()
print("\n=== 도서 목록 ===")
print(f"{'ID':<5} {'제목':<20} {'저자':<10} {'가격':<10} {'재고':<5}")
print("-" * 60)
for book in books:
book_id, title, author, isbn, price, stock, pub_date = book
print(f"{book_id:<5} {title:<20} {author:<10} {price:>8,}원 {stock:>3}권")
print(f"\n총 {len(books)}권의 도서가 등록되어 있습니다.")
conn.close()
출력:
1
2
3
4
5
6
7
8
9
10
11
12
도서 테이블 생성 완료!
3권의 도서 추가 완료!
=== 도서 목록 ===
ID 제목 저자 가격 재고
------------------------------------------------------------
1 파이썬 정복 홍길동 25,000원 10권
2 데이터베이스 기초 김철수 30,000원 5권
3 웹 개발 완벽 가이드 이영희 35,000원 8권
총 3권의 도서가 등록되어 있습니다.
문제 2: 회원 가입 시스템
과제: 사용자 회원 정보를 저장하는 테이블을 만들고 회원 가입 기능을 구현하세요.
요구사항:
members테이블 생성- id: 자동 증가 기본 키
- username: 사용자명 (고유값, 필수)
- email: 이메일 (고유값, 필수)
- password: 비밀번호 (필수)
- join_date: 가입일 (자동으로 현재 시간)
- is_active: 활성 상태 (기본값 1)
- 회원 가입 함수 작성:
- 사용자 입력받기 (username, email, password)
- 데이터 검증 (빈 값 체크)
- DB에 저장
- 성공/실패 메시지 출력
- 3명 이상 회원 가입 후 전체 회원 목록 출력
💡 힌트
UNIQUE로 username과 email 중복 방지DEFAULT CURRENT_TIMESTAMP로 가입일 자동 설정try-except로 중복 회원 에러 처리- 입력값 검증:
if not username or not email
✅ 정답
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
import sqlite3
def create_members_table():
"""회원 테이블 생성"""
conn = sqlite3.connect('users.db')
cursor = conn.cursor()
cursor.execute('''
CREATE TABLE IF NOT EXISTS members (
id INTEGER PRIMARY KEY AUTOINCREMENT,
username TEXT UNIQUE NOT NULL,
email TEXT UNIQUE NOT NULL,
password TEXT NOT NULL,
join_date TEXT DEFAULT CURRENT_TIMESTAMP,
is_active INTEGER DEFAULT 1
)
''')
conn.commit()
conn.close()
print("회원 테이블 생성 완료!\n")
def register_member(username, email, password):
"""회원 가입 함수"""
# 입력값 검증
if not username or not email or not password:
print("❌ 모든 정보를 입력해주세요!")
return False
try:
conn = sqlite3.connect('users.db')
cursor = conn.cursor()
cursor.execute('''
INSERT INTO members (username, email, password)
VALUES (?, ?, ?)
''', (username, email, password))
conn.commit()
conn.close()
print(f"✅ {username}님, 회원가입 완료!")
return True
except sqlite3.IntegrityError:
print(f"❌ 이미 사용 중인 사용자명 또는 이메일입니다!")
return False
def show_all_members():
"""전체 회원 목록 출력"""
conn = sqlite3.connect('users.db')
cursor = conn.cursor()
cursor.execute('SELECT id, username, email, join_date, is_active FROM members')
members = cursor.fetchall()
print("\n=== 전체 회원 목록 ===")
print(f"{'ID':<5} {'사용자명':<15} {'이메일':<25} {'가입일':<20} {'상태':<5}")
print("-" * 80)
for member in members:
member_id, username, email, join_date, is_active = member
status = "활성" if is_active else "비활성"
print(f"{member_id:<5} {username:<15} {email:<25} {join_date:<20} {status:<5}")
print(f"\n총 {len(members)}명의 회원이 가입했습니다.")
conn.close()
# 메인 실행
if __name__ == "__main__":
# 1. 테이블 생성
create_members_table()
# 2. 회원 가입
print("=== 회원 가입 ===")
register_member("hong_gil_dong", "[email protected]", "pass1234")
register_member("kim_cheol_su", "[email protected]", "secure5678")
register_member("lee_young_hee", "[email protected]", "mypass9012")
# 중복 회원 테스트
print("\n=== 중복 회원 가입 시도 ===")
register_member("hong_gil_dong", "[email protected]", "pass0000")
# 3. 전체 회원 목록 출력
show_all_members()
출력:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
회원 테이블 생성 완료!
=== 회원 가입 ===
✅ hong_gil_dong님, 회원가입 완료!
✅ kim_cheol_su님, 회원가입 완료!
✅ lee_young_hee님, 회원가입 완료!
=== 중복 회원 가입 시도 ===
❌ 이미 사용 중인 사용자명 또는 이메일입니다!
=== 전체 회원 목록 ===
ID 사용자명 이메일 가입일 상태
--------------------------------------------------------------------------------
1 hong_gil_dong [email protected] 2025-05-12 09:15:30 활성
2 kim_cheol_su [email protected] 2025-05-12 09:15:30 활성
3 lee_young_hee [email protected] 2025-05-12 09:15:30 활성
총 3명의 회원이 가입했습니다.
📝 오늘 배운 내용 정리
- CREATE TABLE: 테이블 구조 정의하고 생성
- 데이터 타입: INTEGER, TEXT, REAL, BLOB, NULL
- 제약조건: PRIMARY KEY, AUTOINCREMENT, NOT NULL, DEFAULT, UNIQUE
- INSERT: 데이터 추가 (단일/다중)
- 보안:
?플레이스홀더로 SQL Injection 방지 - 트랜잭션: commit()으로 변경사항 저장
🔗 관련 자료
📚 이전 학습
Day 72: SQLite 시작하기 ⭐⭐
어제는 SQLite 데이터베이스 연결과 기본 사용법을 배웠습니다!
📚 다음 학습
Day 74: SQL 기본 (SELECT, WHERE) ⭐⭐
내일은 데이터를 조회하고 필터링하는 SELECT와 WHERE를 배웁니다!
“늦었다고 생각할 때가 가장 빠른 시기입니다!” 🚀
Day 73/100 Phase 8: 데이터베이스와 SQL #100DaysOfPython
