1
insert into table_name (attr1, attr2) VALUES 
  (1, 2),
  (3, 4)
;

I want to insert values into this table 'table_name'. But I want to make it dynamic. I have values in array form in ruby, like this:

[[1, 2], [3, 4]]

How do I pass a ruby array to sql query as values? I am using rails and postgres.

3 Answers 3

3

You can use Arel::InsertManager to generate a SQL insert statement:

def insert_list(table_name:, columns:, values:)
  Arel::InsertManager.new.tap do |manager|
    table = Arel::Table.new(table_name)
    manager.into(table)
    columns.each do |name|
      manager.columns << table[name.to_sym]
    end
    manager.values = manager.create_values_list(values)
  end
end
insert_list(
   table_name: :foos, 
   columns: [:bar, :baz],
   values: [[1, 2], [3, 4], [5, 6], [7, 8], [9, 10]]
).to_sql

# => "INSERT INTO \"foos\" (\"bar\", \"baz\") VALUES (1, 2), (3, 4), (5, 6), (7, 8), (9, 10)"
Sign up to request clarification or add additional context in comments.

6 Comments

Absolutely beautiful. Only recommendation would be arel_table[name] to arel_table[name.to_sym] just to ensure this works whether or not columns are initially symbols.
Thanks and good suggestion @engineersmnky.
Thanks but these are too many lines and I don't know how optimal it would be. I have done it using gsub, I will post my answer
@AsbahIshaq why don't you try actually benchmarking it? The advantage of Arel is that it's portable and handles quoting. I doubt that using gsub! On a huge string will actually perform much better. ruby-doc.org/stdlib-2.5.3/libdoc/benchmark/rdoc/Benchmark.html
@max add a little Bobby tables and see how that impacts things :)
|
2

Assuming you have a model you can use ActiveRecord's insert_all

Model.insert_all([{attr1: 1, attr2: 2}, {attr1: 3, attr2: 4}])

2 Comments

This would be the preferred way if you actually have a model as it will use the model for typecasting. It does have a bit more overhead though.
I don't have the model, that's why I need to use sql
0

join with map would work here:

[[1, 2], [3, 4]].map{|inner| inner.join(", ")}
# => ["1, 2", "3, 4"]
[[1, 2], [3, 4]].map{|inner| inner.join(", ")}.join("),\n(")
# => "1, 2),\n(3, 4"
"(" + [[1, 2], [3, 4]].map{|inner| inner.join(", ")}.join("),\n(") + ")"
# => "(1, 2),\n(3, 4)"
puts "(" + [[1, 2], [3, 4]].map{|inner| inner.join(", ")}.join("),\n(") + ")"
# (1, 2),
# (3, 4)

Please note that this is a simple solution. In a production app, you would need to sanitize the array values [[1, 2], [3, 4]] if they were coming from untrusted sources (Users!) to avoid SQL injection attacks. But this seems to be out of the scope of this question.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.