Liquibase:添加唯一约束前删除重复行
解决Liquibase新增唯一约束前清理重复行的问题
我来帮你搞定这个麻烦事!在生产环境不能修改旧changeset的情况下,咱们可以在新增唯一约束的changeset里先加入删除重复数据的逻辑,确保约束能顺利创建。
具体实现步骤
首先,你需要先清理表中的重复行,然后再添加唯一约束。这里假设你要给foo表的target_column列(替换成你的实际列名)添加唯一约束,下面是完整的changeset示例:
<changeSet id="123" author="me"> <!-- 预检查:只有当存在重复行时才执行后续操作 --> <preConditions onFail="MARK_RAN"> <sqlCheck expectedResult="0"> SELECT COUNT(*) FROM ( SELECT target_column FROM foo GROUP BY target_column HAVING COUNT(*) > 1 ) AS duplicate_rows; </sqlCheck> </preConditions> <!-- 删除重复行:保留每个重复组中ID最大的那条记录(可根据需求调整) --> <sql> DELETE FROM foo WHERE id NOT IN ( SELECT MAX(id) FROM foo GROUP BY target_column HAVING COUNT(*) > 1 ) AND target_column IN ( SELECT target_column FROM foo GROUP BY target_column HAVING COUNT(*) > 1 ); </sql> <!-- 添加唯一约束 --> <addUniqueConstraint tableName="foo" columnNames="target_column" constraintName="uc_foo_target_column"/> </changeSet>
关键细节说明
- 重复行清理逻辑:上面的SQL会针对
target_column分组,找出重复的记录,只保留每组中id最大的那条(如果你的表没有id列,可以换成其他唯一标识,比如created_at最早/最晚的记录,调整MAX(id)为对应的字段即可)。 - 预检查的作用:添加
<preConditions>可以避免在没有重复行时执行删除操作,让changeset更安全,不会做无用功。 - 多列唯一约束:如果你的唯一约束是由多个列组成的,只需要把
GROUP BY和columnNames里的字段换成对应的多列即可,比如GROUP BY col1, col2和columnNames="col1, col2"。
注意事项
- 执行前一定要备份数据,生产环境操作数据容不得半点马虎!
- 确保这个新的changeset在插入重复数据的旧changeset之后执行,Liquibase会按changeset的id顺序执行,所以id要比旧的大。
- 如果你的数据库是MySQL,注意在子查询中使用表别名避免报错;如果是其他数据库,可能需要微调SQL语法,但核心逻辑是一致的。
内容的提问来源于stack exchange,提问作者lohnns
相关产品推荐
相关产品推荐

