我需要交换具有唯一约束的值。我正在尝试使用update_all函数,如下所示。
from(e in Episode, where: e.show_id == ^id, update: [set: [position: fragment("position + 1")]])
|> Repo.update_all([])
使用时,由于位置重复,我收到错误:
ERROR (unique_violation): duplicate key value violates unique constraint "position_show_id_index"
table: episodes
constraint: position_show_id_index
Key ("position", show_id)=(2, 27) already exists.
如何同时交换这些位置值?
答案 0 :(得分:1)
通常,在SQL中交换唯一索引值没有“好的”方法。
Two known solutions 1)删除并重新插入行,或者 2)将行更新为另一个placholder值,然后再更新它们。
您可以在Ecto中采用类似的方法:
解决方案1:
episode = Repo.get(Episode, id)
next_episode = Repo.get_by(Episode, position: episode.position + 1)
if next_episode, do: Repo.delete(next_episode)
episode
|> Episode.changeset(%{position: episode.position + 1})
|> Repo.update()
if next_episode do
Repo.insert(%Episode{next_episode | position: episode.position})
end
解决方案2: (您需要选择一些“不可能”的值作为占位符。例如,如果position必须为正数,则可以使用负数)
episode = Repo.get(Episode, id)
next_episode = Repo.get_by(Episode, position: episode.position + 1)
if next_episode do
next_episode
|> Episode.changeset(%{position: -1})
|> Repo.update()
end
episode
|> Episode.changeset(%{position: episode.position + 1})
|> Repo.update()
if next_episode do
next_episode
|> Episode.changeset(%{position: episode.position})
|> Repo.update()
end
如果您有任何引用Episode
的外键约束,则第二种解决方案可能更可取。