部署执行 setup:upgrade 报 Duplicate column name,数据库里确实已经有这个字段。看到重复列不要立刻删字段,先弄清楚列是上一次部署加了一半、人工提前加的,还是两个模块都在声明同名字段。
先把报错补丁和真实列定义对上
从异常栈找到具体 Schema Patch、UpgradeSchema 或 declarative schema 文件,再查看数据库列类型、长度、nullable、默认值和索引。字段同名不等于定义一致。
SHOW CREATE TABLE target_tableG
SELECT patch_name
FROM patch_list
WHERE patch_name LIKE '%Vendor\Module%';
patch_list 没记录,但列已经存在,常见原因是补丁执行到 addColumn 后进程中断,事务没有覆盖 DDL,或者有人手工执行了 SQL。此时盲目删除列可能把已经写入的业务数据一起删掉。
再查有没有第二个模块也在加同名列
grep -R "column_name" app/code vendor/*/*/etc/db_schema.xml -n
grep -R "addColumn.*column_name" app/code vendor -n
如果两个自定义模块声明同一列,应该确定列归属并合并设计,而不是靠模块加载顺序碰运气。Declarative schema 与旧 UpgradeSchema 同时维护同一字段,也容易在迁移阶段重复。
处理方式取决于列里有没有数据
列为空、定义错误且确认没有代码使用时,可以在备份和测试验证后删除,让正式补丁重建。列已有数据且定义与代码一致,更安全的做法通常是让补丁先检测列是否存在,或修复补丁登记状态,但必须确认该补丁除了加列之外没有其他步骤。
不要随便往 patch_list 插一条记录跳过补丁。它可能还创建索引、迁移数据或增加约束,只标记完成会留下半套结构。
在数据库副本上完整跑一次升级
修复后从生产结构副本执行 setup:upgrade,检查 db_schema_whitelist、索引和外键,再跑应用回归。最后把人工处理写进部署记录。目标是让下一套相同旧版本数据库也能自动升级,不是只让当前库绕过这一行。

