Hello! Anyone knows how to build such query using Ecto? I’m afraid neither of update_all
or Ecto.Query.update
syntax supports it:
UPDATE
registrations
SET
name = values.column_name
FROM (
VALUES
(1, 'test one'),
(2, 'test two'),
(3, 'test three'),
(4, 'test four')
) AS values (column_id, column_name)
WHERE
values.column_id = registrations.id
Source: Bulk Insert and Update in PostgreSQL | by akhouri | Medium
Thanks!
You can access the UPDATE...FROM...
syntax by using a join in update_all
from(p in Posts,
join: c in Comments, on: c.post_id == p.id,
update: [set: [post_column: c.some_other_column]]
)
|> Repo.update_all([])
But Ecto doesn’t support value lists right now. So your exact example can’t be done.
For some background on why it is a join, this is essentially what Postgres does:
When a FROM clause is present, what essentially happens is that the target table is joined to the tables mentioned in the from_item list, and each output row of the join represents an update operation for the target table. When using FROM you should ensure that the join produces at most one output row for each row to be modified. In other words, a target row shouldn’t join to more than one row from the other table(s). If it does, then only one of the join rows will be used to update the target row, but which one will be used is not readily predictable.
This shows an alternative to value lists using unnest
: Unnest for runtime sorted results | Benjamin Milde
json_to_recordset
is also great, but I don’t have a good example ready.
3 Likes
Thanks for the help, I ended up using the join + unnest approach 
I could be cleaner with some macros but for now it works for my use cases, see the code here: accent/operations_update_all_dynamic.ex at master · mirego/accent · GitHub