[SQL 실습 #3] 주차 관리 시스템 데이터베이스 설계
시간 데이터 다루기와 CASE WHEN 조건문을 배웁니다. 주차 공간, 차량, 주차 기록 테이블로 실시간 요금 계산 시스템을 완성합니다.
시작 전, 워밍업
주차장 요금은 어떻게 실시간으로 계산될까?
입차 시간과 출차 시간 차이로 요금 계산.
30분 이내 무료, 1시간당 2,000원, 하루 최대 20,000원.
시작하며 - 실시간 데이터 관리
지난 글에서는 도서관 대출 시스템을 만들었습니다.
1:N 관계와 JOIN으로 여러 테이블을 연결하는 법을 배웠죠.
이번에는 주차 관리 시스템을 만들어봅니다.
도서관과 다른 점이 뭘까요?
"실시간으로 변하는 데이터"
입차 시간, 출차 시간, 주차 요금... 모두 시간에 따라 달라집니다.
이번 실습에서는 DATETIME 타입과 CASE WHEN 조건문을 배워요.
"지금 어느 차가 어디 주차돼 있나?"를 추적하는 시스템을 만들어봅시다.
ERD 설계하기
주차 관리 시스템에 필요한 것들:
- parking_spaces (주차 공간) - 어디에 주차할 수 있나
- vehicles (차량) - 어떤 차가 왔나
- parking_records (주차 기록) - 언제 들어왔고 언제 나갔나
테이블 구조
1. parking_spaces 테이블
- space_id (공간 ID) - Primary Key
- floor (층)
- section (구역)
- is_available (사용 가능 여부) - 1(사용 가능) / 0(사용 중)
2. vehicles 테이블
- vehicle_id (차량 ID) - Primary Key
- license_plate (차량 번호)
- vehicle_type (차종) - '소형', '중형', '대형'
3. parking_records 테이블
- record_id (기록 ID) - Primary Key
- vehicle_id (차량 ID) - Foreign Key → vehicles.vehicle_id
- space_id (공간 ID) - Foreign Key → parking_spaces.space_id
- entry_time (입차 시간) - DATETIME
- exit_time (출차 시간) - DATETIME (NULL이면 주차 중)
- fee (요금) - INTEGER
parking_spaces, vehicles, parking_records 테이블과 관계선
핵심 포인트
parking_records가 중심 테이블입니다.
2개의 Foreign Key로 vehicles와 parking_spaces를 연결해요.
exit_time이 NULL이면 "아직 주차 중"이라는 의미입니다.
테이블 생성하기
1. parking_spaces 테이블 생성
CREATE TABLE parking_spaces (
space_id INTEGER PRIMARY KEY,
floor INTEGER,
section TEXT,
is_available INTEGER DEFAULT 1
);
is_available INTEGER DEFAULT 1 - 기본값 1 (사용 가능)
주차 공간 테이블 생성
2. vehicles 테이블 생성
CREATE TABLE vehicles (
vehicle_id INTEGER PRIMARY KEY,
license_plate TEXT NOT NULL,
vehicle_type TEXT
);
차량 테이블 생성
3. parking_records 테이블 생성
CREATE TABLE parking_records (
record_id INTEGER PRIMARY KEY,
vehicle_id INTEGER,
space_id INTEGER,
entry_time DATETIME,
exit_time DATETIME,
fee INTEGER,
FOREIGN KEY (vehicle_id) REFERENCES vehicles(vehicle_id),
FOREIGN KEY (space_id) REFERENCES parking_spaces(space_id)
);
코드 설명:
entry_time DATETIME- 입차 시간 (날짜 + 시간)exit_time DATETIME- 출차 시간 (NULL이면 주차 중)fee INTEGER- 요금 (원 단위)
주차 기록 테이블 생성 - Foreign Key 2개 포함
데이터 입력하기
1. parking_spaces 데이터 입력
INSERT INTO parking_spaces (space_id, floor, section, is_available)
VALUES
(1, 1, 'A구역', 1),
(2, 1, 'A구역', 0),
(3, 1, 'B구역', 1),
(4, 2, 'A구역', 1),
(5, 2, 'B구역', 0);
주차 공간 5개 데이터 입력 완료
Browse Data 탭에서 확인:
2번, 5번 공간은 사용 중 (is_available = 0)
2. vehicles 데이터 입력
INSERT INTO vehicles (vehicle_id, license_plate, vehicle_type)
VALUES
(1, '12가3456', '소형'),
(2, '34나5678', '중형'),
(3, '56다7890', '대형');
차량 3대 데이터 입력 완료
Browse Data 탭에서 확인:
소형, 중형, 대형 차량 각 1대씩 등록됨
3. parking_records 데이터 입력
INSERT INTO parking_records (record_id, vehicle_id, space_id, entry_time, exit_time, fee)
VALUES
(1, 1, 2, '2026-02-16 09:00:00', NULL, NULL),
(2, 2, 5, '2026-02-16 10:30:00', NULL, NULL),
(3, 3, 3, '2026-02-16 08:00:00', '2026-02-16 12:00:00', 8000);
데이터 설명:
- record 1: 소형차(1)가 2번 공간에 09:00 입차, 아직 주차 중 (exit_time NULL)
- record 2: 중형차(2)가 5번 공간에 10:30 입차, 아직 주차 중
- record 3: 대형차(3)가 3번 공간에 08:00 입차 → 12:00 출차, 요금 8000원
주차 기록 3건 입력 완료
Browse Data 탭에서 확인:
exit_time이 NULL인 기록 = 현재 주차 중
CASE WHEN - 조건부 값 계산
이제 핵심 기능을 만들어봅시다.
차종별로 다른 요금을 자동 계산하는 쿼리예요.
요금 정책
- 소형: 시간당 1,000원
- 중형: 시간당 1,500원
- 대형: 시간당 2,000원
CASE WHEN 쿼리
SELECT
vehicles.license_plate AS 차량번호,
vehicles.vehicle_type AS 차종,
parking_records.entry_time AS 입차시간,
parking_records.exit_time AS 출차시간,
CASE
WHEN vehicles.vehicle_type = '소형' THEN 1000
WHEN vehicles.vehicle_type = '중형' THEN 1500
WHEN vehicles.vehicle_type = '대형' THEN 2000
ELSE 0
END AS 시간당요금
FROM parking_records
JOIN vehicles ON parking_records.vehicle_id = vehicles.vehicle_id;
코드 설명:
CASE- 조건문 시작WHEN 조건 THEN 값- "조건이 참이면 이 값"ELSE 0- 모든 조건이 거짓이면 0END AS 시간당요금- 결과를 '시간당요금'이라는 컬럼명으로 표시
차종에 따라 다른 요금을 계산하는 CASE WHEN 쿼리
실행 결과
소형 1000원, 중형 1500원, 대형 2000원으로 자동 계산됨
실전 응용
여기에 주차 시간을 계산하는 함수를 더하면,
"4시간 주차 × 1500원 = 6000원"처럼 실제 요금까지 계산할 수 있어요.
유용한 쿼리 예시
1. 현재 주차 중인 차량 조회
SELECT
vehicles.license_plate AS 차량번호,
parking_spaces.floor AS 층,
parking_spaces.section AS 구역,
parking_records.entry_time AS 입차시간
FROM parking_records
JOIN vehicles ON parking_records.vehicle_id = vehicles.vehicle_id
JOIN parking_spaces ON parking_records.space_id = parking_spaces.space_id
WHERE parking_records.exit_time IS NULL;
WHERE exit_time IS NULL - 아직 출차하지 않은 기록만 필터링
2. 주차 가능 공간 조회
SELECT
floor AS 층,
section AS 구역,
space_id AS 공간번호
FROM parking_spaces
WHERE is_available = 1;
결과: 1번, 3번, 4번 공간이 비어있음
축하합니다!
여러분은 실시간 데이터 관리 시스템을 만들었습니다.
배운 내용 정리:
- ✅ DATETIME 타입 - 날짜와 시간 데이터 저장
- ✅ NULL 활용 - exit_time이 NULL이면 주차 중
- ✅ CASE WHEN - 조건에 따라 다른 값 계산
- ✅ 복합 JOIN - 3개 테이블 연결
실생활 응용
이 구조를 응용하면 다양한 실시간 시스템을 만들 수 있습니다.
예를 들어:
- 회의실 예약: rooms(회의실), reservations(예약), users(사용자)
- 기기 대여: equipment(기기), rentals(대여), members(회원)
- 작업 시간 추적: tasks(작업), time_logs(시간 기록), employees(직원)
레오파드 게코 케이지 관리라면?
cages(케이지), geckos(개체), housing_logs(배치 기록)으로
"어느 개체가 어느 케이지에 언제부터 있었는지" 이력을 관리할 수 있어요.
다음 글 예고
다음 실습에서는 병원 예약 시스템을 만들어봅니다.
이번엔 더 복잡한 비즈니스 로직을 다뤄요.
"같은 시간에 같은 의사에게 2명 예약 불가"
이런 제약 조건을 데이터베이스로 어떻게 표현할까요?
다음 글에서 만나요! 👋
