sql - 我们可以更改生产中所有迁移的主键吗?
问题描述
我正在尝试将表主键 id 更改为 uuid。但问题是数据已经在生产中。可以选择重新编写整个迁移,但随后我们丢失了已有的数据。
此外,该表彼此之间的关联太多。那么有没有办法处理这种情况呢?
为此,我们将 phoenix 和 elixir 与 postgres 一起使用。
解决方案
是的。可以通过几个步骤完成任务,其中一些对数据库执行原始 SQL。
- 迁移 1 在数据库中创建新列,唯一的,不是空的,类型
:uuid
(正常迁移)并用唯一值填充它(例如,使用ecto UUID 生成器) - 迁移 2 用于
Ecto.Adapters.SQL.query/4
重新分配表中的主键¹ - 迁移 3 更新引用该表的所有其他表,方法是删除外键,然后更新值 from
id
touuid
,然后创建一个指向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
推荐阅读
- php - 将表单发布数据发送到会话变量
- google-app-engine - 如何将 Java 8 App Engine Flexible 迁移到 App Engine Standard?
- linux-device-driver - 如何读取设备树中保留内存的地址
- python - wxpython在鼠标点击时打开第二帧没有响应
- javascript - 如何字符串化新的 Map()?
- java - 如何在前一个或下一个工作日运行 Quartz 调度程序
- c# - 如何压缩成 ASCII 可读文本?
- python - 在 Python 中加入多个异步生成器
- php - 如果用户登录 Laravel,则显示模式
- javascript - 如何在悬停时显示 PNG 图层