---
date: 2026-04-02
type: database
severity: high
tags: [prisma, migration, schema-drift, db-push]
---

# Prisma Schema 漂移修复：db push + resolve 比修复迁移文件更可靠

## 问题

绩效模块的 11 个迁移文件和 UAT/production 数据库状态严重不一致（之前用 db push 直接推过结构，迁移被 resolve --applied 跳过）。需要让数据库和 Prisma schema 对齐。

## 尝试方案 A：生成修复迁移文件（失败）

1. `prisma migrate diff --script` 生成 SQL
2. 给每条语句加 IF EXISTS / DO $$ EXCEPTION 容错
3. 反复测试 → 反复失败：
   - `ALTER TABLE` 表不存在时报错（IF EXISTS 只作用于 CONSTRAINT 不作用于 TABLE）
   - `ALTER TYPE ADD VALUE` 不能在事务块（DO $$）内执行
   - `CREATE INDEX` 依赖的列可能还没加（ADD COLUMN 在 DO $$ 里被异常跳过）
   - 两个环境数据库状态不同，同一个 SQL 文件不可能两边都跑通

## 采用方案 B：db push + resolve（成功）

```bash
# 1. 强制对齐数据库结构
npx prisma db push --accept-data-loss

# 2. 标记迁移文件为已应用
npx prisma migrate resolve --applied <migration_name>

# 3. 验证
npx prisma migrate status  # → Database schema is up to date!
```

## 规则

1. **当迁移文件和数据库状态严重不一致时，不要试图生成"安全"的修复迁移** — 两个环境状态不同，一个 SQL 文件不可能同时适配
2. **直接用 db push 对齐，然后 resolve 标记** — 简单、可靠、两个环境分别处理
3. **db push --accept-data-loss 前要确认被删的数据是否还有价值** — 在这个场景里旧表/旧列都是 PRD 标 Out of Scope 的废弃数据
4. **以后不要用 db push 替代 migrate dev** — 这次的漂移就是之前滥用 db push 导致的

## 经验

- `ALTER TYPE ADD VALUE` 不能在 DO $$ BEGIN ... END $$ 块内执行（PostgreSQL 限制）
- PostgreSQL 12+ 支持 `ADD VALUE IF NOT EXISTS`
- `ALTER TABLE x DROP CONSTRAINT IF EXISTS y` 的 IF EXISTS 只作用于 constraint，表不存在照样报错
- sed 做 SQL 改写极易出错，Python 脚本也不靠谱（语句边界判断复杂），不如直接换方案
