[Python 100일 챌린지] Day 75 - SQL 기본: UPDATE, DELETE
데이터베이스의 데이터를 수정하고 삭제하는 SQL UPDATE와 DELETE 문을 배워봅시다! SELECT로 조회만 할 수 있다면, UPDATE/DELETE로 데이터를 관리할 수 있어야 진정한 데이터베이스 활용이 가능합니다. 실무에서는 안전한 데이터 수정/삭제가 매우 중요하므로 신중하게 학습해주세요! (25분 완독 ⭐⭐⭐)
🎯 오늘의 학습 목표
📚 사전 지식
🎯 학습 목표 1: UPDATE 문으로 데이터 수정하기
한 줄 설명
UPDATE = 테이블의 기존 데이터를 수정하는 SQL 명령어
데이터베이스에 이미 저장된 데이터의 값을 변경할 때 사용합니다.
UPDATE 기본 문법
1
2
3
UPDATE 테이블명
SET 컬럼명 = 새로운값
WHERE 조건;
⚠️ 주의: WHERE 절을 생략하면 테이블의 모든 행이 수정됩니다!
Python에서 UPDATE 사용하기
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
import sqlite3
# 데이터베이스 연결
conn = sqlite3.connect('students.db')
cursor = conn.cursor()
# 학생 테이블 생성 및 데이터 삽입
cursor.execute('''
CREATE TABLE IF NOT EXISTS students (
id INTEGER PRIMARY KEY,
name TEXT NOT NULL,
age INTEGER,
grade TEXT
)
''')
# 샘플 데이터 삽입
students_data = [
(1, '홍길동', 20, 'A'),
(2, '김철수', 21, 'B'),
(3, '이영희', 19, 'A'),
(4, '박민수', 22, 'C')
]
cursor.executemany('INSERT OR REPLACE INTO students VALUES (?, ?, ?, ?)', students_data)
conn.commit()
print("=== 수정 전 데이터 ===")
cursor.execute('SELECT * FROM students')
for row in cursor.fetchall():
print(row)
# UPDATE 실행 - 홍길동의 나이를 25로 변경
cursor.execute('''
UPDATE students
SET age = 25
WHERE name = '홍길동'
''')
conn.commit()
print("\n=== 수정 후 데이터 ===")
cursor.execute('SELECT * FROM students')
for row in cursor.fetchall():
print(row)
conn.close()
출력:
1
2
3
4
5
6
7
8
9
10
11
=== 수정 전 데이터 ===
(1, '홍길동', 20, 'A')
(2, '김철수', 21, 'B')
(3, '이영희', 19, 'A')
(4, '박민수', 22, 'C')
=== 수정 후 데이터 ===
(1, '홍길동', 25, 'A') # 나이가 20 → 25로 변경됨
(2, '김철수', 21, 'B')
(3, '이영희', 19, 'A')
(4, '박민수', 22, 'C')
여러 컬럼 동시 수정
1
2
3
4
5
6
7
8
9
10
11
12
# 홍길동의 나이와 학점을 동시에 수정
cursor.execute('''
UPDATE students
SET age = 26, grade = 'A+'
WHERE name = '홍길동'
''')
conn.commit()
print("=== 여러 컬럼 수정 후 ===")
cursor.execute('SELECT * FROM students WHERE name = "홍길동"')
print(cursor.fetchone())
# (1, '홍길동', 26, 'A+')
🎯 학습 목표 2: WHERE 조건으로 특정 행만 수정하기
WHERE 절의 중요성
WHERE 절을 사용하면 조건에 맞는 특정 행만 수정할 수 있습니다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
import sqlite3
conn = sqlite3.connect('students.db')
cursor = conn.cursor()
# 예제 1: 특정 학생의 학점 수정
cursor.execute('''
UPDATE students
SET grade = 'B+'
WHERE name = '김철수'
''')
conn.commit()
print("=== 김철수의 학점 변경 ===")
cursor.execute('SELECT * FROM students WHERE name = "김철수"')
print(cursor.fetchone())
# (2, '김철수', 21, 'B+')
조건부 UPDATE 예제
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
# 예제 2: 나이가 21 이상인 학생들의 학점을 한 단계 올리기
cursor.execute('''
UPDATE students
SET grade = 'A'
WHERE age >= 21
''')
conn.commit()
print("\n=== 나이 21 이상 학생들 학점 변경 ===")
cursor.execute('SELECT * FROM students WHERE age >= 21')
for row in cursor.fetchall():
print(row)
# 예제 3: 여러 조건 사용 (AND, OR)
cursor.execute('''
UPDATE students
SET grade = 'A+'
WHERE age >= 20 AND name = '홍길동'
''')
conn.commit()
print("\n=== 복합 조건으로 수정 ===")
cursor.execute('SELECT * FROM students WHERE name = "홍길동"')
print(cursor.fetchone())
conn.close()
UPDATE된 행 개수 확인
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
import sqlite3
conn = sqlite3.connect('students.db')
cursor = conn.cursor()
# UPDATE 실행
cursor.execute('''
UPDATE students
SET grade = 'A'
WHERE age >= 21
''')
# 영향받은 행 개수 확인
affected_rows = cursor.rowcount
print(f"수정된 행의 개수: {affected_rows}개")
conn.commit()
conn.close()
🎯 학습 목표 3: DELETE 문으로 데이터 삭제하기
한 줄 설명
DELETE = 테이블에서 행을 삭제하는 SQL 명령어
더 이상 필요 없는 데이터를 데이터베이스에서 영구적으로 제거합니다.
DELETE 기본 문법
1
2
DELETE FROM 테이블명
WHERE 조건;
⚠️ 경고: WHERE 절을 생략하면 테이블의 모든 데이터가 삭제됩니다!
Python에서 DELETE 사용하기
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
import sqlite3
conn = sqlite3.connect('students.db')
cursor = conn.cursor()
print("=== 삭제 전 데이터 ===")
cursor.execute('SELECT * FROM students')
for row in cursor.fetchall():
print(row)
# 특정 학생 삭제
cursor.execute('''
DELETE FROM students
WHERE name = '박민수'
''')
conn.commit()
print("\n=== 삭제 후 데이터 ===")
cursor.execute('SELECT * FROM students')
for row in cursor.fetchall():
print(row)
# 삭제된 행 개수 확인
print(f"\n삭제된 행: {cursor.rowcount}개")
conn.close()
출력:
1
2
3
4
5
6
7
8
9
10
11
12
=== 삭제 전 데이터 ===
(1, '홍길동', 26, 'A+')
(2, '김철수', 21, 'B+')
(3, '이영희', 19, 'A')
(4, '박민수', 22, 'C')
=== 삭제 후 데이터 ===
(1, '홍길동', 26, 'A+')
(2, '김철수', 21, 'B+')
(3, '이영희', 19, 'A')
삭제된 행: 1개
조건부 DELETE
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
import sqlite3
conn = sqlite3.connect('students.db')
cursor = conn.cursor()
# 예제 1: 나이가 특정 값 미만인 학생 삭제
cursor.execute('''
DELETE FROM students
WHERE age < 20
''')
conn.commit()
print(f"20세 미만 학생 삭제: {cursor.rowcount}개")
# 예제 2: 학점이 C인 학생 삭제
cursor.execute('''
DELETE FROM students
WHERE grade = 'C'
''')
conn.commit()
print(f"C 학점 학생 삭제: {cursor.rowcount}개")
# 예제 3: 여러 조건으로 삭제
cursor.execute('''
DELETE FROM students
WHERE age > 25 OR grade = 'F'
''')
conn.commit()
print(f"복합 조건 삭제: {cursor.rowcount}개")
conn.close()
🎯 학습 목표 4: TRUNCATE vs DELETE 이해하기
DELETE vs TRUNCATE 비교
| 항목 | DELETE | TRUNCATE |
|---|---|---|
| 용도 | 선택적 행 삭제 | 전체 데이터 삭제 |
| WHERE 사용 | 가능 | 불가능 |
| 속도 | 느림 (행별 삭제) | 빠름 (테이블 재생성) |
| 복구 | 가능 (트랜잭션) | 어려움 |
| ID 초기화 | 유지 | 초기화 |
💡 주의: SQLite는 TRUNCATE를 지원하지 않습니다. 대신
DELETE FROM 테이블명사용!
전체 데이터 삭제 (SQLite)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
import sqlite3
conn = sqlite3.connect('students.db')
cursor = conn.cursor()
# 방법 1: DELETE로 전체 삭제
cursor.execute('DELETE FROM students')
conn.commit()
print("모든 데이터가 삭제되었습니다.")
# 방법 2: DROP 후 재생성 (TRUNCATE 대안)
cursor.execute('DROP TABLE IF EXISTS students')
cursor.execute('''
CREATE TABLE students (
id INTEGER PRIMARY KEY,
name TEXT NOT NULL,
age INTEGER,
grade TEXT
)
''')
conn.commit()
print("테이블을 재생성했습니다.")
conn.close()
안전한 삭제 패턴
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
import sqlite3
def safe_delete(conn, table_name, condition, values):
"""안전한 삭제를 위한 함수"""
cursor = conn.cursor()
# 1. 삭제 전 확인
query = f'SELECT * FROM {table_name} WHERE {condition}'
cursor.execute(query, values)
rows = cursor.fetchall()
if not rows:
print("삭제할 데이터가 없습니다.")
return 0
print(f"=== 삭제 대상 ({len(rows)}개) ===")
for row in rows:
print(row)
# 2. 사용자 확인
confirm = input("\n정말 삭제하시겠습니까? (yes/no): ")
if confirm.lower() != 'yes':
print("삭제가 취소되었습니다.")
return 0
# 3. 삭제 실행
delete_query = f'DELETE FROM {table_name} WHERE {condition}'
cursor.execute(delete_query, values)
conn.commit()
deleted_count = cursor.rowcount
print(f"\n{deleted_count}개의 행이 삭제되었습니다.")
return deleted_count
# 사용 예제
conn = sqlite3.connect('students.db')
# 나이가 20 미만인 학생 안전하게 삭제
safe_delete(conn, 'students', 'age < ?', (20,))
conn.close()
💡 실전 팁 & 주의사항
💡 Tip 1: 항상 WHERE 절 사용하기
1
2
3
4
5
# ❌ 위험한 코드 - 모든 데이터가 수정됨!
cursor.execute('UPDATE students SET grade = "A"') # WHERE 없음!
# ✅ 안전한 코드 - 조건 명시
cursor.execute('UPDATE students SET grade = "A" WHERE age >= 90')
💡 Tip 2: UPDATE/DELETE 전에 SELECT로 확인
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
import sqlite3
conn = sqlite3.connect('students.db')
cursor = conn.cursor()
# 1단계: SELECT로 먼저 확인
cursor.execute('SELECT * FROM students WHERE age < 20')
rows = cursor.fetchall()
print(f"삭제 대상: {len(rows)}개")
for row in rows:
print(row)
# 2단계: 확인 후 DELETE
if len(rows) > 0:
confirm = input("삭제하시겠습니까? (yes/no): ")
if confirm == 'yes':
cursor.execute('DELETE FROM students WHERE age < 20')
conn.commit()
print("삭제 완료!")
conn.close()
💡 Tip 3: 트랜잭션으로 안전하게 처리
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
import sqlite3
conn = sqlite3.connect('students.db')
cursor = conn.cursor()
try:
# 트랜잭션 시작
cursor.execute('BEGIN TRANSACTION')
# 여러 UPDATE/DELETE 작업
cursor.execute('UPDATE students SET grade = "A" WHERE age >= 90')
cursor.execute('DELETE FROM students WHERE age < 18')
# 모두 성공하면 커밋
conn.commit()
print("작업 완료!")
except Exception as e:
# 에러 발생 시 롤백
conn.rollback()
print(f"에러 발생, 롤백됨: {e}")
finally:
conn.close()
💡 Tip 4: 백업의 중요성
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
import sqlite3
import shutil
from datetime import datetime
# 백업 생성
def backup_database(db_path):
timestamp = datetime.now().strftime('%Y%m%d_%H%M%S')
backup_path = f"{db_path}.backup_{timestamp}"
shutil.copy2(db_path, backup_path)
print(f"백업 생성: {backup_path}")
return backup_path
# 위험한 작업 전 백업
db_path = 'students.db'
backup_path = backup_database(db_path)
# 작업 수행
conn = sqlite3.connect(db_path)
cursor = conn.cursor()
try:
cursor.execute('DELETE FROM students WHERE grade = "F"')
conn.commit()
print("삭제 완료!")
except Exception as e:
print(f"에러 발생: {e}")
# 필요시 백업에서 복원
finally:
conn.close()
💡 Tip 5: 소프트 삭제 (Soft Delete) 패턴
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
import sqlite3
from datetime import datetime
conn = sqlite3.connect('students.db')
cursor = conn.cursor()
# 삭제 플래그를 위한 컬럼 추가
cursor.execute('''
ALTER TABLE students
ADD COLUMN deleted_at TEXT DEFAULT NULL
''')
# 실제 삭제 대신 deleted_at 설정 (소프트 삭제)
cursor.execute('''
UPDATE students
SET deleted_at = ?
WHERE name = '홍길동'
''', (datetime.now().isoformat(),))
conn.commit()
# 삭제되지 않은 데이터만 조회
cursor.execute('SELECT * FROM students WHERE deleted_at IS NULL')
active_students = cursor.fetchall()
print("활성 학생:", active_students)
# 삭제된 데이터 조회 (복구 가능)
cursor.execute('SELECT * FROM students WHERE deleted_at IS NOT NULL')
deleted_students = cursor.fetchall()
print("삭제된 학생:", deleted_students)
conn.close()
🧪 연습 문제
문제 1: 상품 재고 관리 시스템
과제: 상품 데이터베이스에서 재고를 업데이트하고 품절 상품을 삭제하는 시스템을 만드세요.
초기 데이터:
1
2
3
4
5
6
7
products = [
(1, '노트북', 10, 1200000),
(2, '마우스', 50, 25000),
(3, '키보드', 0, 80000),
(4, '모니터', 5, 350000),
(5, '헤드셋', 0, 120000)
]
요구사항:
- products 테이블 생성 (id, name, stock, price)
- 초기 데이터 삽입
- 노트북 5개 판매 (재고 감소)
- 마우스 가격 10% 인상
- 재고가 0인 상품 삭제
- 전체 상품 목록 출력
💡 힌트
- UPDATE로 재고 감소:
SET stock = stock - 5 - 가격 인상:
SET price = price * 1.1 - 재고 0 삭제:
DELETE WHERE stock = 0
✅ 정답
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
import sqlite3
# 데이터베이스 연결
conn = sqlite3.connect('shop.db')
cursor = conn.cursor()
# 1. products 테이블 생성
cursor.execute('''
CREATE TABLE IF NOT EXISTS products (
id INTEGER PRIMARY KEY,
name TEXT NOT NULL,
stock INTEGER DEFAULT 0,
price INTEGER NOT NULL
)
''')
# 2. 초기 데이터 삽입
products = [
(1, '노트북', 10, 1200000),
(2, '마우스', 50, 25000),
(3, '키보드', 0, 80000),
(4, '모니터', 5, 350000),
(5, '헤드셋', 0, 120000)
]
cursor.executemany('INSERT OR REPLACE INTO products VALUES (?, ?, ?, ?)', products)
conn.commit()
print("=== 초기 재고 ===")
cursor.execute('SELECT * FROM products')
for row in cursor.fetchall():
print(f"ID: {row[0]}, 상품: {row[1]}, 재고: {row[2]}, 가격: {row[3]:,}원")
# 3. 노트북 5개 판매
cursor.execute('''
UPDATE products
SET stock = stock - 5
WHERE name = '노트북'
''')
conn.commit()
print("\n노트북 5개 판매 완료!")
# 4. 마우스 가격 10% 인상
cursor.execute('''
UPDATE products
SET price = price * 1.1
WHERE name = '마우스'
''')
conn.commit()
print("마우스 가격 10% 인상 완료!")
# 5. 재고가 0인 상품 삭제
cursor.execute('SELECT * FROM products WHERE stock = 0')
out_of_stock = cursor.fetchall()
print(f"\n=== 품절 상품 ({len(out_of_stock)}개) ===")
for row in out_of_stock:
print(f"삭제 예정: {row[1]}")
cursor.execute('DELETE FROM products WHERE stock = 0')
conn.commit()
print(f"{cursor.rowcount}개 상품 삭제 완료!")
# 6. 전체 상품 목록 출력
print("\n=== 최종 재고 ===")
cursor.execute('SELECT * FROM products')
for row in cursor.fetchall():
print(f"ID: {row[0]}, 상품: {row[1]}, 재고: {row[2]}, 가격: {row[3]:,}원")
conn.close()
출력:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
=== 초기 재고 ===
ID: 1, 상품: 노트북, 재고: 10, 가격: 1,200,000원
ID: 2, 상품: 마우스, 재고: 50, 가격: 25,000원
ID: 3, 상품: 키보드, 재고: 0, 가격: 80,000원
ID: 4, 상품: 모니터, 재고: 5, 가격: 350,000원
ID: 5, 상품: 헤드셋, 재고: 0, 가격: 120,000원
노트북 5개 판매 완료!
마우스 가격 10% 인상 완료!
=== 품절 상품 (2개) ===
삭제 예정: 키보드
삭제 예정: 헤드셋
2개 상품 삭제 완료!
=== 최종 재고 ===
ID: 1, 상품: 노트북, 재고: 5, 가격: 1,200,000원
ID: 2, 상품: 마우스, 재고: 50, 가격: 27,500원
ID: 4, 상품: 모니터, 재고: 5, 가격: 350,000원
문제 2: 회원 탈퇴 시스템
과제: 회원 데이터베이스에서 비활성 회원을 관리하는 시스템을 만드세요.
초기 데이터:
1
2
3
4
5
6
7
members = [
(1, 'user1@example.com', '홍길동', '2024-01-15', 1),
(2, 'user2@example.com', '김철수', '2024-02-20', 1),
(3, 'user3@example.com', '이영희', '2023-06-10', 0),
(4, 'user4@example.com', '박민수', '2024-03-05', 1),
(5, 'user5@example.com', '최지훈', '2023-01-01', 0)
]
요구사항:
- members 테이블 생성 (id, email, name, join_date, is_active)
- 초기 데이터 삽입
- 비활성 회원(is_active=0) 목록 조회
- 특정 회원을 비활성화 (홍길동)
- 2023년 가입 + 비활성 회원 삭제
- 전체 활성 회원 출력
💡 힌트
- 비활성화:
UPDATE SET is_active = 0 - 날짜 비교:
WHERE join_date LIKE '2023%' - 복합 조건:
WHERE ... AND ...
✅ 정답
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
import sqlite3
conn = sqlite3.connect('members.db')
cursor = conn.cursor()
# 1. members 테이블 생성
cursor.execute('''
CREATE TABLE IF NOT EXISTS members (
id INTEGER PRIMARY KEY,
email TEXT UNIQUE NOT NULL,
name TEXT NOT NULL,
join_date TEXT NOT NULL,
is_active INTEGER DEFAULT 1
)
''')
# 2. 초기 데이터 삽입
members = [
(1, 'user1@example.com', '홍길동', '2024-01-15', 1),
(2, 'user2@example.com', '김철수', '2024-02-20', 1),
(3, 'user3@example.com', '이영희', '2023-06-10', 0),
(4, 'user4@example.com', '박민수', '2024-03-05', 1),
(5, 'user5@example.com', '최지훈', '2023-01-01', 0)
]
cursor.executemany('INSERT OR REPLACE INTO members VALUES (?, ?, ?, ?, ?)', members)
conn.commit()
print("=== 전체 회원 ===")
cursor.execute('SELECT * FROM members')
for row in cursor.fetchall():
status = "활성" if row[4] == 1 else "비활성"
print(f"{row[2]} ({row[1]}) - 가입: {row[3]}, 상태: {status}")
# 3. 비활성 회원 조회
print("\n=== 비활성 회원 ===")
cursor.execute('SELECT * FROM members WHERE is_active = 0')
for row in cursor.fetchall():
print(f"{row[2]} ({row[1]}) - 가입: {row[3]}")
# 4. 홍길동 비활성화
cursor.execute('''
UPDATE members
SET is_active = 0
WHERE name = '홍길동'
''')
conn.commit()
print("\n홍길동 회원 비활성화 완료!")
# 5. 2023년 가입 + 비활성 회원 삭제
print("\n=== 삭제 대상 (2023년 가입 + 비활성) ===")
cursor.execute('''
SELECT * FROM members
WHERE join_date LIKE '2023%' AND is_active = 0
''')
delete_targets = cursor.fetchall()
for row in delete_targets:
print(f"{row[2]} ({row[1]}) - 가입: {row[3]}")
cursor.execute('''
DELETE FROM members
WHERE join_date LIKE '2023%' AND is_active = 0
''')
conn.commit()
print(f"\n{cursor.rowcount}명의 회원이 삭제되었습니다.")
# 6. 전체 활성 회원 출력
print("\n=== 최종 활성 회원 ===")
cursor.execute('SELECT * FROM members WHERE is_active = 1')
for row in cursor.fetchall():
print(f"{row[2]} ({row[1]}) - 가입: {row[3]}")
conn.close()
출력:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
=== 전체 회원 ===
홍길동 (user1@example.com) - 가입: 2024-01-15, 상태: 활성
김철수 (user2@example.com) - 가입: 2024-02-20, 상태: 활성
이영희 (user3@example.com) - 가입: 2023-06-10, 상태: 비활성
박민수 (user4@example.com) - 가입: 2024-03-05, 상태: 활성
최지훈 (user5@example.com) - 가입: 2023-01-01, 상태: 비활성
=== 비활성 회원 ===
이영희 (user3@example.com) - 가입: 2023-06-10
최지훈 (user5@example.com) - 가입: 2023-01-01
홍길동 회원 비활성화 완료!
=== 삭제 대상 (2023년 가입 + 비활성) ===
이영희 (user3@example.com) - 가입: 2023-06-10
최지훈 (user5@example.com) - 가입: 2023-01-01
2명의 회원이 삭제되었습니다.
=== 최종 활성 회원 ===
김철수 (user2@example.com) - 가입: 2024-02-20
박민수 (user4@example.com) - 가입: 2024-03-05
📝 오늘 배운 내용 정리
- UPDATE: SET으로 데이터 수정, WHERE로 조건 지정
- DELETE: FROM으로 테이블 지정, WHERE로 삭제 범위 한정
- 안전한 수정/삭제: SELECT로 먼저 확인, 트랜잭션 활용
- 백업: 중요한 작업 전 반드시 백업 생성
- 소프트 삭제: deleted_at 플래그로 복구 가능한 삭제
🔗 관련 자료
📚 이전 학습
Day 74: SQL 기본 - SELECT, WHERE ⭐⭐⭐
어제는 SELECT로 데이터를 조회하고 WHERE로 조건을 지정하는 방법을 배웠습니다!
📚 다음 학습
Day 76: SQL 고급 - JOIN ⭐⭐⭐⭐
내일은 여러 테이블을 연결하는 JOIN을 배웁니다!
“늦었다고 생각할 때가 가장 빠른 시기입니다!” 🚀
Day 75/100 Phase 8: 데이터베이스와 SQL #100DaysOfPython
