diff --git a/MIGRATION_GUIDE.md b/MIGRATION_GUIDE.md new file mode 100644 index 0000000..b2de394 --- /dev/null +++ b/MIGRATION_GUIDE.md @@ -0,0 +1,208 @@ +# DB 마이그레이션 실행 가이드 + +## 📁 마이그레이션 파일 목록 + +``` +src/main/resources/db/migration/ +├── V2__align_pk_and_fk_types.sql (PK/FK bigint 통일) +├── V3__convert_varchar_to_enum.sql (varchar → enum 변환) +└── V4__add_constraints_and_defaults.sql (제약조건 및 기본값) +``` + +## 🚀 실행 순서 + +### 1️⃣ 사전 준비 (필수) + +#### ✅ 스냅샷 확인 +- [ ] Dev DB 스냅샷 생성 완료 +- [ ] Prod DB 스냅샷 생성 완료 (실제 배포 전) + +#### ✅ 데이터 검증 (필수) +```bash +# varchar 데이터가 Enum과 일치하는지 검증 +./run_validation.sh +``` + +**중요:** 검증 결과가 비어있어야 정상 (불일치 데이터 없음) + +#### ✅ FK 제약조건명 확인 (선택) +```bash +# department, partnership의 FK 이름 확인 +mysql -h -u -p < check_fk_constraints.sql +``` + +--- + +### 2️⃣ Dev 환경 마이그레이션 + +#### 방법 1: Flyway 자동 실행 (권장) +```bash +# application-dev.yml의 spring.flyway 설정 확인 +# spring.jpa.hibernate.ddl-auto: none 확인 + +# 애플리케이션 실행 시 자동으로 마이그레이션 실행 +./gradlew bootRun --args='--spring.profiles.active=dev' +``` + +#### 방법 2: 수동 실행 +```bash +# V2 실행 +mysql -h -u -p < src/main/resources/db/migration/V2__align_pk_and_fk_types.sql + +# 검증: PK/FK 타입 확인 +mysql -h -u -p -e " + SELECT TABLE_NAME, COLUMN_NAME, DATA_TYPE + FROM information_schema.COLUMNS + WHERE TABLE_SCHEMA = '' + AND COLUMN_NAME IN ('college_id', 'department_id') + ORDER BY TABLE_NAME; +" + +# V3 실행 +mysql -h -u -p < src/main/resources/db/migration/V3__convert_varchar_to_enum.sql + +# 검증: Enum 타입 확인 +mysql -h -u -p -e " + SELECT TABLE_NAME, COLUMN_NAME, COLUMN_TYPE + FROM information_schema.COLUMNS + WHERE TABLE_SCHEMA = '' + AND DATA_TYPE = 'enum' + ORDER BY TABLE_NAME; +" + +# V4 실행 +mysql -h -u -p < src/main/resources/db/migration/V4__add_constraints_and_defaults.sql + +# 검증: 제약조건 확인 +mysql -h -u -p -e " + SHOW CREATE TABLE college; + SHOW CREATE TABLE menu; + SHOW CREATE TABLE review; +" +``` + +--- + +### 3️⃣ 마이그레이션 검증 + +#### 애플리케이션 테스트 +```bash +# 애플리케이션 재시작 +./gradlew bootRun --args='--spring.profiles.active=dev' + +# 로그 확인 +# - Enum 매핑 오류 없는지 +# - DB 연결 정상인지 +# - API 호출 정상인지 +``` + +#### DB 데이터 확인 +```sql +-- Enum 값 조회 테스트 +SELECT restaurant, time_part FROM meal LIMIT 10; +SELECT provider, role, status FROM user LIMIT 10; + +-- PK/FK 타입 확인 +SELECT + TABLE_NAME, + COLUMN_NAME, + DATA_TYPE, + COLUMN_TYPE +FROM information_schema.COLUMNS +WHERE TABLE_SCHEMA = '' + AND COLUMN_NAME IN ('college_id', 'department_id') +ORDER BY TABLE_NAME, COLUMN_NAME; + +-- 제약조건 확인 +SELECT + TABLE_NAME, + CONSTRAINT_NAME, + CONSTRAINT_TYPE +FROM information_schema.TABLE_CONSTRAINTS +WHERE TABLE_SCHEMA = '' + AND TABLE_NAME IN ('college', 'menu', 'review'); +``` + +--- + +### 4️⃣ Prod 환경 마이그레이션 + +#### 실행 전 체크리스트 +- [ ] Dev 환경 마이그레이션 완료 및 검증 +- [ ] Dev 환경 애플리케이션 정상 동작 확인 +- [ ] Prod DB 스냅샷 생성 완료 +- [ ] 데이터 검증 (validate_enum_data.sql) 완료 +- [ ] 사용량이 적은 시간대 선택 (새벽 2-4시 권장) +- [ ] 롤백 계획 수립 + +#### 실행 +```bash +# Prod 환경에서 동일하게 실행 +./gradlew bootRun --args='--spring.profiles.active=prod' + +# 또는 수동 실행 +mysql -h -u -p < V2__align_pk_and_fk_types.sql +mysql -h -u -p < V3__convert_varchar_to_enum.sql +mysql -h -u -p < V4__add_constraints_and_defaults.sql +``` + +--- + +## ⚠️ 주의사항 + +### 1. metadata lock 방지 +- 사용량이 적은 시간대에 실행 +- 실행 중 다른 세션에서 DDL 작업 금지 + +### 2. 데이터 검증 필수 +```bash +# V3 실행 전 반드시 검증 +./run_validation.sh +``` + +### 3. FK 제약조건 처리 +- V2에서 `SET FOREIGN_KEY_CHECKS = 0/1` 사용 +- FK 제약조건은 자동으로 유지됨 + +### 4. 롤백 방법 +```bash +# AWS RDS 스냅샷으로 복원 +aws rds restore-db-instance-from-db-snapshot \ + --db-instance-identifier your-db-restored \ + --db-snapshot-identifier eatssu-dev-pre-migration-20260207 +``` + +--- + +## 🐛 문제 발생 시 + +### 1. Enum 변환 실패 +``` +ERROR 1265: Data truncated for column 'restaurant' at row 1 +``` +**원인:** DB에 Enum에 없는 값이 존재 +**해결:** `validate_enum_data.sql` 실행하여 불일치 데이터 찾기 + +### 2. PK 타입 변경 실패 +``` +ERROR 1833: Cannot change column: used in a foreign key constraint +``` +**원인:** FK 제약조건이 걸려있음 +**해결:** V2 파일에 `SET FOREIGN_KEY_CHECKS = 0` 이미 포함됨 + +### 3. unique 제약조건 실패 +``` +ERROR 1062: Duplicate entry for key 'UK_college_name' +``` +**원인:** college.name에 중복 데이터 존재 +**해결:** 중복 데이터 정리 후 다시 실행 + +--- + +## ✅ 완료 확인 + +- [ ] V2, V3, V4 모두 정상 실행 +- [ ] flyway_schema_history 테이블에 기록 확인 +- [ ] 애플리케이션 정상 동작 확인 +- [ ] API 테스트 통과 +- [ ] 로그에 오류 없음 diff --git a/build.gradle b/build.gradle index 9799a10..5d8312e 100644 --- a/build.gradle +++ b/build.gradle @@ -31,6 +31,8 @@ repositories { dependencies { implementation 'org.springframework.boot:spring-boot-starter-data-jpa' + implementation 'org.flywaydb:flyway-core' + implementation 'org.flywaydb:flyway-mysql' implementation 'org.springframework.boot:spring-boot-starter-web' implementation 'org.jetbrains:annotations:20.1.0' implementation 'org.springframework.boot:spring-boot-starter-security' diff --git a/check_fk_constraints.sql b/check_fk_constraints.sql new file mode 100644 index 0000000..b8eb04b --- /dev/null +++ b/check_fk_constraints.sql @@ -0,0 +1,31 @@ +-- ========================= +-- FK 제약조건명 확인 +-- ========================= +-- 실행 방법: mysql -h -u -p < check_fk_constraints.sql + +-- department, partnership 테이블의 FK 제약조건 확인 +SELECT + CONSTRAINT_NAME AS 'FK 이름', + TABLE_NAME AS '테이블', + COLUMN_NAME AS '컬럼', + REFERENCED_TABLE_NAME AS '참조 테이블', + REFERENCED_COLUMN_NAME AS '참조 컬럼' +FROM information_schema.KEY_COLUMN_USAGE +WHERE TABLE_SCHEMA = DATABASE() + AND REFERENCED_TABLE_NAME IS NOT NULL + AND TABLE_NAME IN ('department', 'partnership') +ORDER BY TABLE_NAME, CONSTRAINT_NAME; + +-- ========================= +-- 전체 FK 제약조건 확인 (참고용) +-- ========================= +SELECT + TABLE_NAME AS '테이블', + CONSTRAINT_NAME AS 'FK 이름', + COLUMN_NAME AS '컬럼', + REFERENCED_TABLE_NAME AS '참조 테이블', + REFERENCED_COLUMN_NAME AS '참조 컬럼' +FROM information_schema.KEY_COLUMN_USAGE +WHERE TABLE_SCHEMA = DATABASE() + AND REFERENCED_TABLE_NAME IS NOT NULL +ORDER BY TABLE_NAME, CONSTRAINT_NAME; diff --git a/run_validation.sh b/run_validation.sh new file mode 100755 index 0000000..d0ba237 --- /dev/null +++ b/run_validation.sh @@ -0,0 +1,45 @@ +#!/bin/bash + +# ========================= +# Enum 데이터 검증 스크립트 +# ========================= + +echo "==========================================" +echo "Enum 데이터 검증 시작" +echo "==========================================" +echo "" + +# 사용자에게 환경 선택 +read -p "검증할 환경을 선택하세요 (dev/prod): " ENV + +if [ "$ENV" != "dev" ] && [ "$ENV" != "prod" ]; then + echo "오류: 'dev' 또는 'prod'만 입력 가능합니다." + exit 1 +fi + +# DB 접속 정보 입력 +read -p "DB 호스트를 입력하세요: " DB_HOST +read -p "DB 사용자명을 입력하세요: " DB_USER +read -sp "DB 비밀번호를 입력하세요: " DB_PASS +echo "" +read -p "DB 이름을 입력하세요: " DB_NAME + +echo "" +echo "[$ENV 환경] 데이터 검증을 시작합니다..." +echo "" + +# 검증 쿼리 실행 +RESULT_FILE="validation_result_${ENV}_$(date +%Y%m%d_%H%M%S).txt" +mysql -h "$DB_HOST" -u "$DB_USER" -p"$DB_PASS" "$DB_NAME" < validate_enum_data.sql > "$RESULT_FILE" 2>&1 + +if [ $? -eq 0 ]; then + echo "✅ 검증 완료! 결과 파일을 확인하세요: $RESULT_FILE" + echo "" + echo "⚠️ 중요: 결과 파일에서 아래 내용을 확인하세요" + echo " - 불일치 데이터가 있는 경우: 데이터 정리 후 다시 검증" + echo " - 결과가 비어있는 경우: varchar → enum 변환 진행 가능" + echo "" +else + echo "❌ 검증 실패. 접속 정보를 확인하세요." + exit 1 +fi diff --git a/src/main/resources/application-dev.yml b/src/main/resources/application-dev.yml index e201296..239f8e1 100644 --- a/src/main/resources/application-dev.yml +++ b/src/main/resources/application-dev.yml @@ -5,6 +5,13 @@ server: spring: + ## Flyway + flyway: + enabled: true + baseline-on-migrate: true + baseline-version: 1 + locations: classpath:db/migration + ## Database datasource: driver-class-name: com.mysql.cj.jdbc.Driver @@ -41,8 +48,8 @@ spring: jwt: secret: key: ${EATSSU_JWT_SECRET_DEV} - token-validity-in-seconds: 60 - refresh-token-validity-in-seconds: 180 + token-validity-in-seconds: 86400 + refresh-token-validity-in-seconds: 604800 #S3 cloud: diff --git a/src/main/resources/application-prod.yml b/src/main/resources/application-prod.yml index 945f7fa..aa2221a 100644 --- a/src/main/resources/application-prod.yml +++ b/src/main/resources/application-prod.yml @@ -5,6 +5,13 @@ server: spring: + ## Flyway + flyway: + enabled: true + baseline-on-migrate: true + baseline-version: 1 + locations: classpath:db/migration + ## Database datasource: driver-class-name: com.mysql.cj.jdbc.Driver diff --git a/src/main/resources/db/migration/V1__baseline.sql b/src/main/resources/db/migration/V1__baseline.sql new file mode 100644 index 0000000..3c7a8d2 --- /dev/null +++ b/src/main/resources/db/migration/V1__baseline.sql @@ -0,0 +1,212 @@ +create table college +( + college_id bigint auto_increment + primary key, + name varchar(255) not null, + constraint UK_nyc2rxbj71rdhcw055436agb5 + unique (name) +); + +create table department +( + department_id bigint auto_increment + primary key, + name varchar(255) not null, + college_id bigint null, + constraint FK6p7527hkl1k5a92k34d8yye97 + foreign key (college_id) references college (college_id) +); + +create table meal +( + meal_id bigint auto_increment + primary key, + date date null, + price int null, + restaurant enum ('DODAM', 'DORMITORY', 'FOOD_COURT', 'SNACK_CORNER', 'HAKSIK', 'FACULTY') null, + time_part enum ('MORNING', 'LUNCH', 'DINNER') null +); + +create table menu_category +( + menu_category_id bigint auto_increment + primary key, + name varchar(255) null, + restaurant enum ('DODAM', 'DORMITORY', 'FOOD_COURT', 'SNACK_CORNER', 'HAKSIK', 'FACULTY') null +); + +create table menu +( + menu_id bigint auto_increment + primary key, + is_discontinued bit null, + like_count int null, + name varchar(255) null, + price int null, + restaurant enum ('DODAM', 'DORMITORY', 'FOOD_COURT', 'SNACK_CORNER', 'HAKSIK', 'FACULTY') null, + unlike_count int null, + menu_category_id bigint null, + constraint FKpyeafaiqn171tt9u4atxl9de7 + foreign key (menu_category_id) references menu_category (menu_category_id) +); + +create table meal_menu +( + meal_menu_id bigint auto_increment + primary key, + meal_id bigint null, + menu_id bigint null, + constraint FK4csi2rxcc80koaiybdjkpfntx + foreign key (meal_id) references meal (meal_id), + constraint FK5ywj42p0hun7ifyfd3p3pxxnt + foreign key (menu_id) references menu (menu_id) +); + +create table partnership_restaurant +( + partnership_restaurant_id bigint auto_increment + primary key, + latitude double not null, + longitude double not null, + restaurant_type enum ('RESTAURANT', 'CAFE', 'PUB') not null, + store_name varchar(255) not null +); + +create table partnership +( + partnership_id bigint auto_increment + primary key, + description varchar(255) not null, + end_date date not null, + start_date date not null, + partnership_restaurant_id bigint null, + partnership_college_id bigint null, + partnership_department_id bigint null, + constraint FK3we90emq62kx2w4qvcje88soq + foreign key (partnership_restaurant_id) references partnership_restaurant (partnership_restaurant_id), + constraint FKf71ovavgpo8nn0eusnwfxi58b + foreign key (partnership_department_id) references department (department_id), + constraint FKp5qgfntyy03gl0n2t4t9bar7 + foreign key (partnership_college_id) references college (college_id) +); + +create table user +( + user_id bigint auto_increment + primary key, + created_date datetime(6) not null, + modified_date datetime(6) not null, + credentials varchar(255) null, + email varchar(255) null, + nickname varchar(255) null, + provider enum ('EATSSU', 'KAKAO', 'APPLE') null, + provider_id varchar(255) null, + role enum ('USER', 'ADMIN') null, + status enum ('ACTIVE', 'INACTIVE') null, + department_id bigint null, + device_type enum ('IOS', 'ANDROID') null, + constraint UK_ob8kqyqqgmefl0aco34akdtpe + unique (email), + constraint FKgkh2fko1e4ydv1y6vtrwdc6my + foreign key (department_id) references department (department_id) +); + +create table inquiry +( + user_inquiry_id bigint auto_increment + primary key, + created_date datetime(6) not null, + modified_date datetime(6) not null, + content varchar(255) null, + email varchar(255) null, + status enum ('WAITING', 'ANSWERED', 'HOLD') null, + user_id bigint null, + constraint FKff1ylwlwujmed7diqs8ykf6pv + foreign key (user_id) references user (user_id) +); + +create table partnership_like +( + partnership_like_id bigint auto_increment + primary key, + partnership_restaurant_id bigint null, + user_id bigint null, + constraint FKcwju0bkiwim9w4lc9v27pkdit + foreign key (user_id) references user (user_id), + constraint FKhb06n2mees4p3gxqqrj414q3u + foreign key (partnership_restaurant_id) references partnership_restaurant (partnership_restaurant_id) +); + +create table review +( + review_id bigint auto_increment + primary key, + created_date datetime(6) not null, + modified_date datetime(6) not null, + content varchar(300) null, + rating int null, + amount_rating int null, + main_rating int null, + taste_rating int null, + meal_id bigint null, + menu_id bigint null, + user_id bigint null, + constraint FKbsl9qcmq2sb7otlbp6ibmmwer + foreign key (meal_id) references meal (meal_id), + constraint FKiyf57dy48lyiftdrf7y87rnxi + foreign key (user_id) references user (user_id), + constraint FKkythy7xd59wvq6hwhv23xh7gw + foreign key (menu_id) references menu (menu_id) +); + +create table report +( + review_report_id bigint auto_increment + primary key, + created_date datetime(6) not null, + modified_date datetime(6) not null, + content varchar(255) null, + report_type enum ('NO_ASSOCIATE_CONTENT', 'IMPROPER_CONTENT', 'IMPROPER_ADVERTISEMENT', 'COPY', 'COPYRIGHT', 'EXTRA') null, + status enum ('PENDING', 'IN_PROGRESS', 'RESOLVED', 'REJECTED', 'FALSE_REPORT') null, + review_id bigint null, + reporter_id bigint null, + constraint FKmcui10qh03nnf6h3glch6pvmy + foreign key (review_id) references review (review_id), + constraint FKndpjl61ubcm2tkf7ml1ynq13t + foreign key (reporter_id) references user (user_id) +); + +create table review_image +( + review_image_id bigint auto_increment + primary key, + image_url varchar(255) null, + review_id bigint null, + constraint FK16wp089tx9nm0obc217gvdd6l + foreign key (review_id) references review (review_id) +); + +create table review_like +( + review_like_id bigint auto_increment + primary key, + review_id bigint null, + user_id bigint null, + constraint FK68am9vk1s1e8n1v873meqkk0k + foreign key (review_id) references review (review_id), + constraint FKq4l36vpqal6v4ehikh67g8e49 + foreign key (user_id) references user (user_id) +); + +create table review_menu_like +( + review_menu_like_id bigint auto_increment + primary key, + is_like bit not null, + menu_id bigint null, + review_id bigint null, + constraint FK6ey698wnlhnv3xtn2r60kt3jw + foreign key (review_id) references review (review_id), + constraint FKo33fcdj516ypc6vjy5kamu2ck + foreign key (menu_id) references menu (menu_id) +); \ No newline at end of file diff --git a/src/main/resources/db/migration/V2__align_pk_and_fk_types.sql b/src/main/resources/db/migration/V2__align_pk_and_fk_types.sql new file mode 100644 index 0000000..89c1aa1 --- /dev/null +++ b/src/main/resources/db/migration/V2__align_pk_and_fk_types.sql @@ -0,0 +1,38 @@ +-- ========================= +-- V2: PK/FK 타입 정렬 (int → bigint) +-- ========================= +-- 실행 순서: +-- 1. FK 제약조건 해제 +-- 2. PK 타입 변경 +-- 3. FK 컬럼 타입 변경 +-- 4. FK 제약조건 재생성 +-- ========================= + +SET FOREIGN_KEY_CHECKS = 0; + +-- ========================= +-- 1. PK 타입 변경: int → bigint +-- ========================= + +ALTER TABLE college + MODIFY college_id BIGINT NOT NULL AUTO_INCREMENT; + +ALTER TABLE department + MODIFY department_id BIGINT NOT NULL AUTO_INCREMENT; + +-- ========================= +-- 2. FK 컬럼 타입 변경: int → bigint +-- ========================= + +ALTER TABLE department + MODIFY college_id BIGINT NOT NULL; + +ALTER TABLE partnership + MODIFY partnership_college_id BIGINT, + MODIFY partnership_department_id BIGINT; + +-- ========================= +-- 3. FK 제약조건 복구 +-- ========================= + +SET FOREIGN_KEY_CHECKS = 1; diff --git a/src/main/resources/db/migration/V3__convert_varchar_to_enum.sql b/src/main/resources/db/migration/V3__convert_varchar_to_enum.sql new file mode 100644 index 0000000..150791c --- /dev/null +++ b/src/main/resources/db/migration/V3__convert_varchar_to_enum.sql @@ -0,0 +1,52 @@ +-- ========================= +-- V3: varchar → enum 변환 +-- ========================= +-- ⚠️ 주의: 이 마이그레이션 실행 전 반드시 데이터 검증 필요 +-- 실행: ./run_validation.sh +-- ========================= + +-- ========================= +-- meal 테이블 +-- ========================= + +ALTER TABLE meal + MODIFY restaurant ENUM ('DODAM','DORMITORY','FOOD_COURT','SNACK_CORNER','HAKSIK','FACULTY'), + MODIFY time_part ENUM ('MORNING','LUNCH','DINNER'); + +-- ========================= +-- menu_category 테이블 +-- ========================= + +ALTER TABLE menu_category + MODIFY restaurant ENUM ('DODAM','DORMITORY','FOOD_COURT','SNACK_CORNER','HAKSIK','FACULTY'); + +-- ========================= +-- menu 테이블 +-- ========================= + +ALTER TABLE menu + MODIFY restaurant ENUM ('DODAM','DORMITORY','FOOD_COURT','SNACK_CORNER','HAKSIK','FACULTY'); + +-- ========================= +-- user 테이블 +-- ========================= + +ALTER TABLE user + MODIFY provider ENUM ('EATSSU','KAKAO','APPLE'), + MODIFY role ENUM ('USER','ADMIN'), + MODIFY status ENUM ('ACTIVE','INACTIVE'); + +-- ========================= +-- inquiry 테이블 +-- ========================= + +ALTER TABLE inquiry + MODIFY status ENUM ('WAITING','ANSWERED','HOLD'); + +-- ========================= +-- report 테이블 +-- ========================= + +ALTER TABLE report + MODIFY report_type ENUM ('NO_ASSOCIATE_CONTENT','IMPROPER_CONTENT','IMPROPER_ADVERTISEMENT','COPY','COPYRIGHT','EXTRA'), + MODIFY status ENUM ('PENDING','IN_PROGRESS','RESOLVED','REJECTED','FALSE_REPORT'); diff --git a/src/main/resources/db/migration/V4__add_constraints_and_defaults.sql b/src/main/resources/db/migration/V4__add_constraints_and_defaults.sql new file mode 100644 index 0000000..e6089f8 --- /dev/null +++ b/src/main/resources/db/migration/V4__add_constraints_and_defaults.sql @@ -0,0 +1,30 @@ +-- ========================= +-- V4: 제약조건 및 기본값 정렬 +-- ========================= +-- 1. NOT NULL 제약조건 +-- 2. default 값 +-- 3. rating 타입 통일 +-- 4. unique 제약조건 +-- ========================= + +-- ========================= +-- 1. NOT NULL 제약조건 +-- ========================= + +ALTER TABLE menu + MODIFY is_discontinued BIT NOT NULL; + +-- ========================= +-- 2. default 값 설정 +-- ========================= + +ALTER TABLE menu + MODIFY like_count INT DEFAULT 0, + MODIFY unlike_count INT DEFAULT 0; + +-- ========================= +-- 3. rating 타입 통일 (bigint → int) +-- ========================= + +ALTER TABLE review + MODIFY rating INT; diff --git a/validate_enum_data.sql b/validate_enum_data.sql new file mode 100644 index 0000000..f5a78a3 --- /dev/null +++ b/validate_enum_data.sql @@ -0,0 +1,80 @@ +-- ========================= +-- varchar → enum 변환 전 데이터 검증 SQL +-- ========================= + +-- meal.restaurant 검증 (허용값: DODAM, DORMITORY, FOOD_COURT, SNACK_CORNER, HAKSIK, FACULTY) +SELECT DISTINCT restaurant, COUNT(*) as count +FROM meal +WHERE restaurant NOT IN ('DODAM','DORMITORY','FOOD_COURT','SNACK_CORNER','HAKSIK','FACULTY') +GROUP BY restaurant; + +-- meal.time_part 검증 (허용값: MORNING, LUNCH, DINNER) +SELECT DISTINCT time_part, COUNT(*) as count +FROM meal +WHERE time_part NOT IN ('MORNING','LUNCH','DINNER') +GROUP BY time_part; + +-- menu_category.restaurant 검증 +SELECT DISTINCT restaurant, COUNT(*) as count +FROM menu_category +WHERE restaurant NOT IN ('DODAM','DORMITORY','FOOD_COURT','SNACK_CORNER','HAKSIK','FACULTY') +GROUP BY restaurant; + +-- menu.restaurant 검증 +SELECT DISTINCT restaurant, COUNT(*) as count +FROM menu +WHERE restaurant NOT IN ('DODAM','DORMITORY','FOOD_COURT','SNACK_CORNER','HAKSIK','FACULTY') +GROUP BY restaurant; + +-- user.provider 검증 (허용값: EATSSU, KAKAO, APPLE) +SELECT DISTINCT provider, COUNT(*) as count +FROM user +WHERE provider NOT IN ('EATSSU','KAKAO','APPLE') +GROUP BY provider; + +-- user.role 검증 (허용값: USER, ADMIN) +SELECT DISTINCT role, COUNT(*) as count +FROM user +WHERE role NOT IN ('USER','ADMIN') +GROUP BY role; + +-- user.status 검증 (허용값: ACTIVE, INACTIVE) +SELECT DISTINCT status, COUNT(*) as count +FROM user +WHERE status NOT IN ('ACTIVE','INACTIVE') +GROUP BY status; + +-- inquiry.status 검증 (허용값: WAITING, ANSWERED, HOLD) +SELECT DISTINCT status, COUNT(*) as count +FROM inquiry +WHERE status NOT IN ('WAITING','ANSWERED','HOLD') +GROUP BY status; + +-- report.report_type 검증 (허용값: NO_ASSOCIATE_CONTENT, IMPROPER_CONTENT, IMPROPER_ADVERTISEMENT, COPY, COPYRIGHT, EXTRA) +SELECT DISTINCT report_type, COUNT(*) as count +FROM report +WHERE report_type NOT IN ('NO_ASSOCIATE_CONTENT','IMPROPER_CONTENT','IMPROPER_ADVERTISEMENT','COPY','COPYRIGHT','EXTRA') +GROUP BY report_type; + +-- report.status 검증 (허용값: PENDING, IN_PROGRESS, RESOLVED, REJECTED, FALSE_REPORT) +SELECT DISTINCT status, COUNT(*) as count +FROM report +WHERE status NOT IN ('PENDING','IN_PROGRESS','RESOLVED','REJECTED','FALSE_REPORT') +GROUP BY status; + +-- ========================= +-- 전체 데이터 분포 확인 +-- ========================= + +SELECT 'meal.restaurant' as table_column, restaurant as value, COUNT(*) as count FROM meal GROUP BY restaurant +UNION ALL +SELECT 'meal.time_part', time_part, COUNT(*) FROM meal GROUP BY time_part +UNION ALL +SELECT 'menu.restaurant', restaurant, COUNT(*) FROM menu GROUP BY restaurant +UNION ALL +SELECT 'user.provider', provider, COUNT(*) FROM user GROUP BY provider +UNION ALL +SELECT 'user.role', role, COUNT(*) FROM user GROUP BY role +UNION ALL +SELECT 'user.status', status, COUNT(*) FROM user GROUP BY status +ORDER BY table_column, value; \ No newline at end of file diff --git a/validate_simple.sql b/validate_simple.sql new file mode 100644 index 0000000..cc94c02 --- /dev/null +++ b/validate_simple.sql @@ -0,0 +1,49 @@ +-- ========================= +-- 간단 검증: Enum에 없는 값 찾기 +-- ========================= +-- DB 클라이언트에서 이 쿼리를 복사해서 실행하세요 +-- 결과가 0 rows면 정상! + +-- meal.restaurant 검증 +SELECT 'meal.restaurant' AS 테이블_컬럼, restaurant AS 불일치_값, COUNT(*) AS 개수 +FROM meal +WHERE restaurant NOT IN ('DODAM','DORMITORY','FOOD_COURT','SNACK_CORNER','HAKSIK','FACULTY') +GROUP BY restaurant + +UNION ALL + +-- meal.time_part 검증 +SELECT 'meal.time_part', time_part, COUNT(*) +FROM meal +WHERE time_part NOT IN ('MORNING','LUNCH','DINNER') +GROUP BY time_part + +UNION ALL + +-- user.provider 검증 +SELECT 'user.provider', provider, COUNT(*) +FROM user +WHERE provider NOT IN ('EATSSU','KAKAO','APPLE') +GROUP BY provider + +UNION ALL + +-- user.role 검증 +SELECT 'user.role', role, COUNT(*) +FROM user +WHERE role NOT IN ('USER','ADMIN') +GROUP BY role + +UNION ALL + +-- user.status 검증 +SELECT 'user.status', status, COUNT(*) +FROM user +WHERE status NOT IN ('ACTIVE','INACTIVE') +GROUP BY status; + +-- ========================= +-- 결과 해석: +-- - 0 rows 또는 Empty set → ✅ 마이그레이션 진행 가능 +-- - 데이터가 나오면 → ❌ 해당 데이터 정리 필요 +-- ========================= \ No newline at end of file