8. SQL INSERT, UPDATE, DELETE 명령어 실습
1. 인트로
데이터를 넣고(INSERT(인서트)), 수정하고(UPDATE(업데이트)), 삭제하는(DELETE(딜리트)) 명령어를 익힌다. 이 세 명령어는 DML(Data Manipulation Language(데이터 매니퓰레이션 랭귀지))에 속하며, 리액트 앱의 회원가입, 정보 수정, 탈퇴 기능의 핵심이다.
2. 실습 DB 준비
import sqlite3
conn = sqlite3.connect("sns.db")
cur = conn.cursor()
cur.execute("""
CREATE TABLE IF NOT EXISTS posts (
id INTEGER PRIMARY KEY AUTOINCREMENT,
username TEXT NOT NULL,
content TEXT NOT NULL,
likes INTEGER DEFAULT 0,
created_at TEXT DEFAULT (datetime('now','localtime'))
)
""")
conn.commit()
print("posts 테이블 생성 완료")
3. SQL INSERT 명령어의 이해 및 실습
3.1. 기본 INSERT
# 게시글 한 개 삽입
cur.execute(
"INSERT INTO posts (username, content) VALUES (?, ?)",
("김철수", "오늘 점심 맛있었다 🍜")
)
conn.commit()
print("게시글 작성 완료, id:", cur.lastrowid)
코드 설명:
- 3행: 값을 넣을 컬럼명을 명시한다. id, likes, created_at은 DEFAULT 값이 있어 생략 가능하다.
- 4행:
?플레이스홀더에 실제 값을 전달한다. - 6행:
cur.lastrowid— 방금 삽입된 행의 id를 반환한다.
3.2. 여러 행 한 번에 삽입 — executemany
sample_posts = [
("이영희", "오늘 운동 완료! 💪"),
("박지민", "새 앨범 나왔다!! 🎵"),
("최수진", "비 오는 날 커피 ☕"),
("홍길동", "파이썬 공부 중 🐍"),
("강민준", "주말 영화 추천 받아요 🎬"),
]
cur.executemany(
"INSERT INTO posts (username, content) VALUES (?, ?)",
sample_posts
)
conn.commit()
print(f"{cur.rowcount}개 게시글 삽입 완료")
코드 설명:
- 1~7행: 삽입할 데이터를 튜플 리스트로 준비한다.
- 9행:
executemany()는 같은 SQL을 리스트 길이만큼 반복 실행한다. - 13행:
cur.rowcount는 영향받은 행의 수를 반환한다.
3.3. 삽입 결과 확인
import pandas as pd
df = pd.read_sql("SELECT * FROM posts", conn)
print(df)
4. SQL UPDATE 명령어의 이해 및 실습
4.1. 단일 행 수정
# id가 1인 게시글의 likes를 10으로 수정
cur.execute("UPDATE posts SET likes = 10 WHERE id = 1")
conn.commit()
print("좋아요 업데이트 완료")
코드 설명:
- 2행:
SET likes = 10— likes 컬럼 값을 10으로 변경한다. - 2행:
WHERE id = 1— id가 1인 행만 수정한다. WHERE가 없으면 전체 행이 수정된다.
4.2. 조건에 맞는 여러 행 수정
# 좋아요 0인 게시글을 1로 초기화
cur.execute("UPDATE posts SET likes = 1 WHERE likes = 0")
conn.commit()
print(f"{cur.rowcount}개 게시글 좋아요 초기화")
4.3. 현재 값 기준으로 수정
# id=2 게시글 좋아요 +5 증가
cur.execute("UPDATE posts SET likes = likes + 5 WHERE id = 2")
conn.commit()
# 확인
cur.execute("SELECT id, username, likes FROM posts WHERE id = 2")
print("수정 후:", cur.fetchone())
코드 설명:
- 2행:
likes = likes + 5— 기존 값에 5를 더한다. 리액트 앱의 좋아요 버튼 클릭 시 사용되는 패턴이다.
5. SQL DELETE 명령어의 이해 및 실습
5.1. 특정 행 삭제
# id가 3인 게시글 삭제
cur.execute("DELETE FROM posts WHERE id = 3")
conn.commit()
print(f"{cur.rowcount}개 게시글 삭제 완료")
코드 설명:
- 2행:
WHERE id = 3— id가 3인 행만 삭제한다. 조건이 없으면 전체 삭제된다.
5.2. 조건으로 여러 행 삭제
# 좋아요 2 이하인 게시글 삭제
cur.execute("DELETE FROM posts WHERE likes <= 2")
conn.commit()
print(f"{cur.rowcount}개 비인기 게시글 삭제")
5.3. 삭제 전 확인 패턴 (권장)
# 삭제 전에 먼저 SELECT로 확인
cur.execute("SELECT id, username, content FROM posts WHERE likes <= 2")
targets = cur.fetchall()
print("삭제 예정 게시글:")
for t in targets:
print(f" id={t[0]} {t[1]}: {t[2]}")
# 확인 후 삭제
ans = input("삭제하시겠습니까? (y/n): ")
if ans.lower() == 'y':
cur.execute("DELETE FROM posts WHERE likes <= 2")
conn.commit()
print("삭제 완료")
else:
print("취소")
코드 설명:
- 2~6행: 삭제 전에 SELECT로 대상을 먼저 확인한다. 실무에서 권장하는 패턴이다.
- 9~13행: 사용자 입력을 받아 최종 확인 후 삭제한다.
6. 트랜잭션(Transaction(트랜잭션)) 이해
트랜잭션은 여러 작업을 하나의 단위로 묶는 개념이다. 모두 성공하거나, 하나라도 실패하면 전체를 되돌린다.
try:
# 게시글 작성 + 작성자 포인트 증가를 하나의 트랜잭션으로 처리
cur.execute("INSERT INTO posts (username, content) VALUES (?, ?)",
("테스트유저", "트랜잭션 테스트 게시글"))
# 의도적 오류 발생 (테스트용)
# cur.execute("UPDATE 없는테이블 SET x=1")
conn.commit() # 모두 성공하면 저장
print("게시글 작성 성공")
except Exception as e:
conn.rollback() # 실패하면 전체 되돌리기
print(f"오류 발생, 되돌림: {e}")
코드 설명:
- 1행:
try블록 안에서 여러 SQL을 실행한다. - 9행: 모두 정상이면
commit()으로 저장한다. - 12행: 하나라도 실패하면
rollback(롤백)으로 이전 상태로 되돌린다.
7. 활용 Plus — 리액트 연동 관점
리액트 SNS 앱의 각 기능과 SQL의 매핑이다.
| 리액트 기능 | SQL 명령 |
|---|---|
| 게시글 작성 | INSERT INTO posts |
| 좋아요 클릭 | UPDATE posts SET likes = likes + 1 WHERE id = ? |
| 게시글 수정 | UPDATE posts SET content = ? WHERE id = ? |
| 게시글 삭제 | DELETE FROM posts WHERE id = ? |
8. 문제풀기
Q1. executemany()를 사용하는 이유는?
동일한 SQL 문을 여러 데이터에 반복 실행할 때 코드를 간결하게 만들고 성능을 향상시키기 위해서이다.
Q2. UPDATE에서 WHERE를 빠뜨리면 어떤 일이 발생하는가?
테이블의 모든 행이 수정된다. 반드시 WHERE로 수정 대상을 지정해야 한다.
Q3. rollback()은 언제 사용하는가?
트랜잭션 도중 오류가 발생했을 때 변경사항 전체를 취소하고 이전 상태로 되돌릴 때 사용한다.
Q4. cur.lastrowid와 cur.rowcount의 차이는?
lastrowid: 마지막으로 INSERT된 행의 id 값을 반환한다. rowcount: 마지막 SQL로 영향받은 행의 수를 반환한다.