我们可以更改生产中所有迁移的主键吗?

时间:2021-05-06 05:47:06

标签: sql postgresql elixir ecto phoenix

我正在尝试将表主键 ID 更改为 uuid。但问题是数据已经在生产中。有一个选项可以重新编写整个迁移,但随后我们丢失了我们已有的数据。

表格之间也有太多关联。那么有没有办法处理这种情况?

为此,我们将 phoenix 和 elixir 与 postgres 结合使用。

1 个答案:

答案 0 :(得分:0)

是的。一个人可能通过几个步骤来完成这项任务,其中一些是针对数据库执行原始 SQL。

  • 迁移 1 在数据库中创建新列,唯一的,非空的,类型 :uuid(正常迁移)用唯一值填充它(使用 UUID 生成器,例如)
  • 迁移 2 使用 Ecto.Adapters.SQL.query/4 重新分配表中的主键¹
  • 迁移 3 通过删除外键 then 更新值从 iduuidthen 创建引用此表的所有其他表指向 uuid²
  • 的新外键

¹ 有点类似于以下几行(未经测试)

defmodule MyRepo.Migrations.ChangeFK do
  def up do
    MyRepo.query("""
    CREATE UNIQUE INDEX CONCURRENTLY foo_pkey_idx ON foo(id);

    ALTER TABLE foos
      DROP CONSTRAINT foo_pkey,
      ADD CONSTRAINT foo_pkey PRIMARY KEY USING INDEX foo_pkey_idx;
    """)
  end

  def down do
    raise "unreversible"
  end
end

² 有点像

defmodule MyRepo.Migrations.AlterFK do
  def up do
    MyRepo.query("""
    ALTER TABLE bars DROP CONSTRAINT foo_pkey;

    UPDATE bars SET foo_id = (SELECT uuid FROM foos WHERE id = foo_id);

    ALTER TABLE bars
      ADD CONSTRAINT foo_pkey
      FOREIGN KEY (foo_id)
      REFERENCES foos (uuid);
    """)
  end

  def down do
    raise "unreversible"
  end
end