I want to use a single query to update many records in my Postgres database using a Ruby hash or array, rather than having to iterate through each record and call a separate update.
# {:id => :color}
my_hash = {
1 => 'red',
2 => 'blue',
3 => 'green'
}
How I don't want to do it because it does three serial queries:
my_hash.each do |id, color|
MyModel.where(id: id).update_all(color: color)
end
How I do want to do it:
MyModel.connection.execute <<-SQL
UPDATE my_models
SET color=something
FROM somehow_using(my_hash)
WHERE maybe_id=something
SQL
You can use case
:
update my_models
set color = case id
when 1 then 'red'
when 2 then 'blue'
when 3 then 'green'
end;
or save the hash in a separate table:
create table my_hash (id int, color text);
insert into my_hash values
(1, 'red'),
(2, 'blue'),
(3, 'green');
update my_models m
set color = h.color
from my_hash h
where h.id = m.id;
One more option, if you know the way to select the hash as jsonb
:
with hash as (
select '{"1": "red", "2": "blue", "3": "green"}'::jsonb h
)
update my_models
set color = value
from hash, jsonb_each_text(h)
where key::int = id;
OP ruby-fying klin's third option:
sql = <<-SQL
with hash as (
select '#{my_hash.to_json}'::jsonb h
)
update my_models
set color = value
from hash, jsonb_each_text(h)
where key::int = id;
SQL
ActiveRecord::Base.connection.execute(sql)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With