fix(테이블타입): TABLE_TYPE_COLUMNS 에 ON CONFLICT 매칭용 UNIQUE INDEX 추가 + 중복 정리
Build & Deploy to K8s / build-and-deploy (push) Successful in 8m27s
Build & Deploy to K8s / build-and-deploy (push) Successful in 8m27s
테이블 타입관리의 모든 쓰기 API (UNIQUE/NOT NULL 토글, 컬럼 설정 저장,
input-type upsert) 가 500 반환. 원인은 mapper SQL 의
ON CONFLICT (TABLE_NAME, COLUMN_NAME, COMPANY_CODE) 가 매칭할 unique
제약/인덱스가 운영 DB 에 존재하지 않아 PG 가
"there is no unique or exclusion constraint matching the ON CONFLICT
specification" 으로 거부.
- StartupSchemaMigrator MIGRATIONS 에 V025 / RUN_090 (1) (2) 추가:
(1) ROW_NUMBER 로 (table, column, company) 중복 행 정리
(운영 메타 DB 실측 2 그룹 / 4 row — 동일 데이터의 NULL updated_date
옛 row 제거. 테넌트 DB 들은 중복 0건).
(2) UX_TABLE_TYPE_COLUMNS_TCC UNIQUE INDEX 생성 (IF NOT EXISTS — 멱등).
- RUN_090_MIGRATION.md 신설.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -250,7 +250,38 @@ public class StartupSchemaMigrator {
|
||||
RENAME COLUMN CODE_CATEGORY TO CODE_INFO;
|
||||
END IF;
|
||||
END $$
|
||||
""",
|
||||
|
||||
// V025 / RUN_090 (1) TABLE_TYPE_COLUMNS 중복 행 정리.
|
||||
// PK 가 id 단일 (varchar) 인데 (TABLE_NAME, COLUMN_NAME, COMPANY_CODE) 에는
|
||||
// UNIQUE 가 없어서 같은 키로 row 가 여러 개 INSERT 된 이력이 있음.
|
||||
// 메타 DB 실측: 35K rows 중 2 그룹 4 row 가 중복. 그 그룹들은 동일 데이터를
|
||||
// updated_date NULL 짜리 옛 row 와 2026-03-16 마지막 갱신 row 가 공존하는 형태.
|
||||
// 가장 최근 (updated_date DESC NULLS LAST, id::bigint DESC) 행만 남기고 제거.
|
||||
// 테넌트 DB 들은 실측상 중복 없음 → DELETE 0건. 멱등 (재실행해도 변화 없음).
|
||||
"""
|
||||
DELETE FROM TABLE_TYPE_COLUMNS
|
||||
WHERE id IN (
|
||||
SELECT id FROM (
|
||||
SELECT id,
|
||||
ROW_NUMBER() OVER (
|
||||
PARTITION BY TABLE_NAME, COLUMN_NAME, COMPANY_CODE
|
||||
ORDER BY UPDATED_DATE DESC NULLS LAST,
|
||||
id::bigint DESC
|
||||
) AS rn
|
||||
FROM TABLE_TYPE_COLUMNS
|
||||
) r
|
||||
WHERE r.rn > 1
|
||||
)
|
||||
""",
|
||||
|
||||
// V025 / RUN_090 (2) ON CONFLICT 매칭용 UNIQUE INDEX 추가.
|
||||
// mapper 의 upsertColumnSettings / upsertNullable / upsertUnique /
|
||||
// upsertColumnInputType 모두 ON CONFLICT (TABLE_NAME, COLUMN_NAME, COMPANY_CODE)
|
||||
// 를 쓰는데 DB 엔 매칭 unique 제약이 없어서 모든 쓰기 API 가 500.
|
||||
// 인덱스 형태로 등록하면 ON CONFLICT 가 인식하고 ADD CONSTRAINT 식의
|
||||
// IF NOT EXISTS 누락 문제도 회피.
|
||||
"CREATE UNIQUE INDEX IF NOT EXISTS UX_TABLE_TYPE_COLUMNS_TCC ON TABLE_TYPE_COLUMNS (TABLE_NAME, COLUMN_NAME, COMPANY_CODE)"
|
||||
);
|
||||
|
||||
@EventListener(ApplicationReadyEvent.class)
|
||||
|
||||
Reference in New Issue
Block a user