Type something to search...

03 SQLite3 라이브러리를 활용한 SQL 명령문 실행

1. 인트로

파이썬의 내장 라이브러리인 sqlite3를 사용하여 SQL 명령문을 실행하는 방법을 배운다. 파일로 저장되는 실제 DB를 만들고, 데이터를 넣고 꺼내는 전체 흐름을 익힌다.


2. SQLite3 라이브러리(Library(라이브러리)) 기초

2.1. 라이브러리란?

라이브러리는 누군가가 미리 만들어 놓은 코드 모음이다. sqlite3는 파이썬 설치 시 자동으로 포함되어 있어 별도 설치가 필요 없다.

1
import sqlite3

이 한 줄로 모든 DB 기능을 사용할 수 있다.

2.2. DB 연결 흐름

1
① connect() → DB 파일 연결(또는 생성)
2
② cursor() → 명령 전달 도구 준비
3
③ execute() → SQL 명령 실행
4
④ commit() → 변경사항 저장 (저장 확인)
5
⑤ close() → DB 연결 종료

3. SQLite3를 활용한 SQL 명령문의 실행 방법 실습

3.1. DB 파일 생성 및 테이블 만들기

1
import sqlite3
2
3
# 1. DB 연결 (파일이 없으면 자동 생성)
4
conn = sqlite3.connect("playlist.db")
5
cur = conn.cursor()
6
7
# 2. 테이블 생성
8
cur.execute("""
9
CREATE TABLE IF NOT EXISTS songs (
10
id INTEGER PRIMARY KEY AUTOINCREMENT,
11
title TEXT NOT NULL,
12
artist TEXT NOT NULL,
13
genre TEXT,
14
play INTEGER DEFAULT 0
15
)
16
""")
17
18
conn.commit()
19
print("테이블 생성 완료!")

코드 설명:

  • 4행: playlist.db 파일을 생성하거나 이미 있으면 연결한다.
  • 5행: cursor(커서)를 생성한다. SQL 명령을 전달하는 통로이다.
  • 9행: IF NOT EXISTS는 테이블이 이미 있으면 오류 없이 넘어가라는 의미이다.
  • 10행: AUTOINCREMENT(오토인크리먼트)는 id를 자동으로 1씩 증가시킨다.
  • 11행: NOT NULL은 이 컬럼에 빈 값을 허용하지 않는다는 의미이다.
  • 13행: DEFAULT 0은 값을 넣지 않으면 자동으로 0이 저장된다는 의미이다.
  • 18행: commit()을 호출해야 변경사항이 실제 파일에 저장된다.

3.2. 데이터 삽입(INSERT(인서트))

1
# 노래 데이터 삽입
2
songs_data = [
3
("Supernova", "aespa", "K-Pop"),
4
("Dynamite", "BTS", "K-Pop"),
5
("Blinding Lights","The Weeknd","Pop"),
6
("GODS", "NewJeans", "K-Pop"),
7
("Levitating", "Dua Lipa", "Pop"),
8
]
9
10
cur.executemany(
11
"INSERT INTO songs (title, artist, genre) VALUES (?, ?, ?)",
12
songs_data
13
)
14
15
conn.commit()
16
print(f"{cur.rowcount}개의 데이터가 삽입되었습니다.")

코드 설명:

  • 2~8행: 삽입할 노래 데이터를 튜플(tuple(튜플)) 목록으로 준비한다.
  • 10행: executemany()는 동일한 SQL을 여러 번 반복 실행할 때 사용한다.
  • 11행: ?는 플레이스홀더(Placeholder(플레이스홀더))이다. 실제 값은 두 번째 인자로 전달된다. SQL 인젝션(Injection(인젝션)) 공격을 방지한다.
  • 15행: rowcount는 마지막으로 실행된 SQL로 영향받은 행의 수를 반환한다.

3.3. 데이터 조회(SELECT(셀렉트))

1
# 전체 조회
2
cur.execute("SELECT * FROM songs")
3
rows = cur.fetchall()
4
5
print("=== 전체 플레이리스트 ===")
6
for row in rows:
7
print(f"[{row[0]}] {row[1]} - {row[2]} ({row[3]})")

실행 결과:

1
=== 전체 플레이리스트 ===
2
[1] Supernova - aespa (K-Pop)
3
[2] Dynamite - BTS (K-Pop)
4
[3] Blinding Lights - The Weeknd (Pop)
5
[4] GODS - NewJeans (K-Pop)
6
[5] Levitating - Dua Lipa (Pop)

코드 설명:

  • 2행: SELECT *는 모든 컬럼을 가져오라는 의미이다.
  • 3행: fetchall()은 조회 결과 전체를 리스트로 반환한다.
  • 6~7행: 각 행(row(로우))은 튜플이다. row[0]은 id, row[1]은 title이다.

3.4. fetchone / fetchall / fetchmany 비교

1
cur.execute("SELECT * FROM songs")
2
3
one = cur.fetchone() # 한 행만 가져온다
4
print("fetchone :", one)
5
6
cur.execute("SELECT * FROM songs")
7
many = cur.fetchmany(3) # 3행만 가져온다
8
print("fetchmany:", many)

코드 설명:

  • 3행: fetchone()은 결과에서 첫 번째 행 하나만 반환한다.
  • 6행: 다시 SELECT를 실행해야 커서가 처음으로 돌아간다.
  • 7행: fetchmany(3)은 지정한 수만큼만 가져온다.

4. 데이터 수정 및 삭제

4.1. 데이터 수정(UPDATE(업데이트))

1
# play 수를 1 증가시킨다
2
cur.execute(
3
"UPDATE songs SET play = play + 1 WHERE title = ?",
4
("Dynamite",)
5
)
6
conn.commit()
7
print("재생횟수 업데이트 완료")

코드 설명:

  • 3행: SET은 수정할 컬럼과 값을 지정한다. WHERE는 수정 대상을 조건으로 필터링한다.
  • 4행: ("Dynamite",) 뒤의 쉼표(,)는 이것이 튜플임을 나타낸다. 필수이다.

4.2. 데이터 삭제(DELETE(딜리트))

1
# 특정 노래 삭제
2
cur.execute("DELETE FROM songs WHERE artist = ?", ("Dua Lipa",))
3
conn.commit()
4
print(f"{cur.rowcount}개 삭제 완료")

코드 설명:

  • 2행: WHERE 조건에 맞는 행만 삭제한다. WHERE가 없으면 테이블의 전체 데이터가 삭제된다.

5. DB 연결 종료

1
conn.close()
2
print("DB 연결 종료")
  • close()를 호출하지 않으면 DB 파일이 잠긴 상태로 남을 수 있다.
  • with 구문을 사용하면 자동으로 닫힌다.
1
# with 구문 사용 예시 (권장)
2
with sqlite3.connect("playlist.db") as conn:
3
cur = conn.cursor()
4
cur.execute("SELECT COUNT(*) FROM songs")
5
cnt = cur.fetchone()[0]
6
print(f"총 {cnt}곡")
7
# with 블록을 벗어나면 자동으로 commit 및 close

코드 설명:

  • 2행: with 구문은 블록이 끝나면 자동으로 commit()close()를 처리한다.
  • 5행: fetchone()[0]은 결과 튜플의 첫 번째 값(개수)만 꺼낸다.

6. 활용 Plus — 리액트 연동 준비

나중에 리액트와 연동할 때, 파이썬 API 서버는 이 playlist.db 파일을 사용한다.

1
리액트 → GET /api/songs → 파이썬 서버 → SELECT * FROM songs → 결과 반환 → 리액트 화면에 표시

지금 만든 playlist.db가 최종 프로젝트의 데이터 저장소가 된다.


7. 문제풀기

INSERT, UPDATE, DELETE 명령은 commit()을 호출해야 실제 파일에 저장된다. commit() 없이 close()하면 변경사항이 사라진다.

SQL 인젝션(Injection(인젝션)) 공격을 방지하기 위해서이다. 값을 문자열로 직접 연결하면 보안 취약점이 생긴다.

fetchone(): 결과 중 첫 번째 행 하나만 반환한다. fetchall(): 결과 전체를 리스트로 반환한다.

WHERE 조건이 없어 테이블의 모든 데이터가 삭제된다. DELETE 명령 사용 시 WHERE 조건을 반드시 확인해야 한다.