【问题标题】:How to bulk insert with Arel?如何使用 Arel 批量插入?
【发布时间】:2016-01-17 20:27:43
【问题描述】:

我有类似以下循环的东西,它创建了许多插入:

table = Arel::Table.new(:users)
users.each do |user|
  manager = Arel::InsertManager.new(ActiveRecord::Base)
  manager.into(table).insert([
    [table[:name], user.name],
    [table[:created_at], user.created_at],
    [table[:updated_at], user.updated_at]
  ])
  # INSERT INTO users (name) VALUES ('a')
  @conn.insert(manager.to_sql)
end

但是,我想找到一种方法来仅获取要插入的值。在这种情况下,我将能够对所有值进行一次插入。

PS:请注意我不想写 sql 字符串(安全问题)。

table = Arel::Table.new(:users)
inserts = []
users.each do |user|
  manager = Arel::InsertManager.new(ActiveRecord::Base)
  manager.into(table).insert([
    [table[:name], user.name],
    [table[:created_at], user.created_at],
    [table[:updated_at], user.updated_at]
  ])
  inserts << "(#{??manage values??})"
end
# INSERT INTO users (name) VALUES ('a'), ('b'), ('c')
@conn.insert(????)

【问题讨论】:

    标签: ruby-on-rails ruby postgresql ruby-on-rails-4 arel


    【解决方案1】:

    本月早些时候出现了一个名为bulk_insert 的库。这应该为您提供您正在寻找的功能:

    Model.bulk_insert do |worker|
      worker.add(...)
      worker.add(...)
      ...
    end
    
    # Produces:
    INSERT INTO models (...) VALUES
      (...),
      (...),
      (...),
      (...),
      ...
    

    由于它是一个相当新的库,而且我还没有机会使用它,所以我不确定它的 Arel 功能。

    【讨论】:

      【解决方案2】:

      您可以使用Active Record Import

      【讨论】:

        【解决方案3】:

        如果您的 AREL 版本已经支持 create_tuple,它将是这样的:

                table = Table.new(:users)
                manager = Arel::InsertManager.new
                manager.into table
        
                manager.columns << table[:id]
                manager.columns << table[:name]
        
                manager.values = manager.create_tuple([
                  manager.create_values(%w{ 1 david }),
                  manager.create_values(%w{ 2 kirs }),
                  manager.create_values(["3", Arel.sql('DEFAULT')], []),
                ])
        
                # INSERT INTO "users" ("id", "name") VALUES ('1', 'david'), ('2', 'kirs'), ('3', DEFAULT)
              end
        

        取自这里:https://github.com/kirs/arel/blob/5d6d14cb6be217abc04253da0fe49721d09e9575/test/test_insert_manager.rb#L31

        【讨论】:

          【解决方案4】:

          查看bulk_insert(感谢@Gavin Miller),我意识到他们使用Rails cote 来防止sql 注入。

          因为我需要定制的东西,所以我不打算购买宝石。因此,如果其他人有类似的要求,我的最终解决方案如下:

          inserts = []
          users.each do |user|
            inserts << %{(
              #{@conn.quote(user.name)},
              #{@conn.quote(user.created_at)},
              #{@conn.quote(user.updated_at)}
            )}
          end
          
          sql = %{
            INSERT INTO users
            (name, created_at, updated_at)
            VALUES #{inserts.join(',')}
          }
          
          @conn.execute(sql)
          

          【讨论】:

            猜你喜欢
            • 2015-09-12
            • 2012-09-28
            • 2012-10-23
            • 1970-01-01
            • 2014-04-13
            • 2015-02-09
            • 2011-06-20
            • 1970-01-01
            • 2013-06-30
            相关资源
            最近更新 更多