CREATE 명령어를 활용한 DB 테이블의 생성
코드 블록의 Try it Yourself 버튼으로 직접 실행할 수 있다.
구문
1. 인트로
데이터를 담을 그릇인 테이블을 만드는 방법을 배운다.
CREATE TABLE 명령은 DB 설계의 시작점이다.
이번 차시에서는 DB Browser for SQLite(디비 브라우저 포 에스큐엘라이트)를 함께 활용하여
테이블 구조를 시각적으로 확인한다.
2. DB Browser for SQLite(디비 브라우저 포 에스큐엘라이트) 활용법
2.1. DB Browser란?
DB Browser for SQLite는 SQLite DB 파일을 시각적으로 열고 확인할 수 있는 무료 도구이다.
- 공식 다운로드: https://sqlitebrowser.org/dl/
- 테이블 구조를 GUI(지유아이)로 확인할 수 있다.
- SQL 명령을 직접 입력하고 결과를 확인할 수 있다.
2.2. 파이썬에서 만든 DB 파일 열기
- DB Browser를 실행한다.
- 상단 메뉴 파일 → 데이터베이스 열기를 클릭한다.
- 파이썬으로 만든
.db파일을 선택한다. - 데이터베이스 구조 탭에서 테이블 목록을 확인한다.
3. CREATE를 활용한 DB 테이블 생성
3.1. CREATE TABLE(크리에이트 테이블) 기본 문법
CREATE TABLE 테이블명 (
컬럼명 데이터타입 제약조건,
컬럼명 데이터타입 제약조건
);
3.2. SQLite 주요 데이터 타입
| 타입 | 설명 | 예시 |
|---|---|---|
| INTEGER(인티저) | 정수 | 나이, 가격, 개수 |
| REAL(리얼) | 소수점 숫자 | 평점, 위도, 경도 |
| TEXT(텍스트) | 문자열 | 이름, 주소, 내용 |
| BLOB(블랍) | 이진 데이터 | 이미지, 파일 |
| NULL(널) | 값 없음 | — |
3.3. 주요 제약조건(Constraint(컨스트레인트))
| 제약조건 | 의미 |
|---|---|
| PRIMARY KEY(프라이머리 키) | 기본키, 테이블에서 유일한 값 |
| AUTOINCREMENT(오토인크리먼트) | 자동으로 1씩 증가 |
| NOT NULL(낫 널) | 빈 값 허용 안 함 |
| UNIQUE(유니크) | 중복값 허용 안 함 |
| DEFAULT 값(디폴트) | 값이 없을 때 기본값 지정 |
| CHECK(체크) | 조건을 만족하는 값만 허용 |
4. 실습: 넷플릭스 클론 DB 설계
리액트 프로젝트의 최종 결과물로 넷플릭스 클론 앱을 만든다고 가정하고 DB를 설계한다.
4.1. users 테이블 생성
import sqlite3
conn = sqlite3.connect("netflix_clone.db")
cur = conn.cursor()
cur.execute("""
CREATE TABLE IF NOT EXISTS users (
id INTEGER PRIMARY KEY AUTOINCREMENT,
username TEXT NOT NULL UNIQUE,
email TEXT NOT NULL UNIQUE,
password TEXT NOT NULL,
plan TEXT DEFAULT 'basic',
created_at TEXT DEFAULT (datetime('now', 'localtime'))
)
""")
conn.commit()
print("users 테이블 생성 완료")
코드 설명:
- 7행:
IF NOT EXISTS— 이미 있으면 오류 없이 넘어간다. - 8행: id는 기본키이며 자동으로 증가한다.
- 9~10행: username과 email은 중복을 허용하지 않는다(
UNIQUE). - 12행: plan(요금제)은 기본값으로 'basic'이 저장된다.
- 13행:
datetime('now', 'localtime')은 현재 시간을 자동 저장하는 SQLite 함수이다.
4.2. contents 테이블 생성
cur.execute("""
CREATE TABLE IF NOT EXISTS contents (
id INTEGER PRIMARY KEY AUTOINCREMENT,
title TEXT NOT NULL,
genre TEXT,
release_yr INTEGER CHECK(release_yr >= 1900),
rating REAL DEFAULT 0.0,
is_series INTEGER DEFAULT 0,
thumbnail TEXT
)
""")
conn.commit()
print("contents 테이블 생성 완료")
코드 설명:
- 6행:
CHECK(release_yr >= 1900)— 출시 연도가 1900 미만이면 저장을 거부한다. - 7행: rating(평점)은 소수점이 있으므로 REAL 타입을 사용한다.
- 8행: is_series(시리즈 여부)는 0(영화) 또는 1(시리즈)로 표현한다. SQLite에는 BOOLEAN(불리언) 타입이 없어 INTEGER로 대신한다.
4.3. watchlist 테이블 생성 (외래키 관계)
cur.execute("""
CREATE TABLE IF NOT EXISTS watchlist (
id INTEGER PRIMARY KEY AUTOINCREMENT,
user_id INTEGER NOT NULL,
content_id INTEGER NOT NULL,
watched_at TEXT DEFAULT (datetime('now', 'localtime')),
FOREIGN KEY (user_id) REFERENCES users(id),
FOREIGN KEY (content_id) REFERENCES contents(id)
)
""")
conn.commit()
print("watchlist 테이블 생성 완료")
코드 설명:
- 4행:
user_id는 users 테이블의 id를 참조한다. - 5행:
content_id는 contents 테이블의 id를 참조한다. - 7~8행:
FOREIGN KEY(포린 키)는 다른 테이블과의 연결을 설정한다. 존재하지 않는 user_id나 content_id는 저장할 수 없다.
5. 테이블 목록 확인
# 생성된 테이블 목록 확인
cur.execute("SELECT name FROM sqlite_master WHERE type='table'")
tables = cur.fetchall()
print("=== 생성된 테이블 목록 ===")
for t in tables:
print(f" - {t[0]}")
실행 결과:
=== 생성된 테이블 목록 ===
- users
- contents
- watchlist
코드 설명:
- 2행:
sqlite_master는 SQLite 내부 시스템 테이블로, 생성된 테이블 정보를 담고 있다. - 2행:
WHERE type='table'로 테이블만 필터링한다.
6. 활용 Plus — 리액트 프로젝트 DB 설계
최종 리액트 프로젝트에서 사용할 전체 테이블 구조이다.
users ──(1:N)──▶ watchlist ◀──(1:N)── contents
(회원 정보) (시청 기록) (콘텐츠 정보)
- 회원 1명이 여러 콘텐츠를 볼 수 있다 (1:N 관계).
- 콘텐츠 1개를 여러 회원이 볼 수 있다 (1:N 관계).
- 이 구조를 이번 차시에서 직접 설계했다.
7. 문제풀기
Q1. AUTOINCREMENT의 역할은?
id 컬럼에 값을 직접 입력하지 않아도 자동으로 1씩 증가하여 저장된다. 새로운 행이 추가될 때마다 이전 최대값 + 1이 자동 부여된다.
Q2. UNIQUE와 PRIMARY KEY의 차이점은?
PRIMARY KEY: 테이블에서 단 하나만 존재하며, NULL을 허용하지 않는다. UNIQUE: 중복값을 허용하지 않지만, 테이블에 여러 컬럼에 적용 가능하며 NULL을 허용한다.
Q3. FOREIGN KEY(포린 키)를 사용하는 이유는?
다른 테이블과의 관계를 설정하여 데이터 무결성을 보장하기 위해서이다. 존재하지 않는 user_id를 watchlist에 저장하는 것을 방지한다.
Q4. SQLite에서 현재 시간을 자동 저장하는 표현식은?
DEFAULT (datetime('now', 'localtime'))