【问题标题】:How to bulk insert data in a table using Rails and a single insert statement如何使用 Rails 和单个插入语句在表中批量插入数据
【发布时间】:2014-06-24 16:47:47
【问题描述】:

我有以下 ActiveRecord 模型,Widget、Merchant、Store、StoresWidget(多对多关联)

class Merchant < ActiveRecord::Base
  has_many :stores
  has_many :widgets
end

class Widget < ActiveRecord::Base
  has_many :stores_widgets
  has_many :stores, :through => :stores_widgets
  belongs_to :merchant
end

class Store < ActiveRecord::Base
  has_many :stores_widgets
  has_many :widgets, :through => :stores_widgets
  belongs_to :merchant
end

class StoresWidget < ActiveRecord::Base
  belongs_to :widget
  belongs_to :store
end

所以对应的表是widgetsmerchantsstoresstores_widgets,其中widgetsstores各有一个id列,stores_widgets有两列store_idwidget_id。一个小部件可以在 1 个或多个商店中使用,并且一个商店可以有许多可用的小部件。某些小部件在所有商店中都可用,有些仅在部分商店中可用。如果 Widget 仅限于商店的子集,则 restricted 列是 true

向商家添加新商店时,我想更新与该商店关联的所有不受限制的小部件。理想情况下,我希望在我的StoresController#create中有这样的代码

class StoresController < ApplicationController
  def create
    # build new store...
    Store.transaction do
      store.save!
      Widget.update_all_unrestricted_widgets_with_store(store)
    end
    render :show
  end
end

update_all_unrestricted_widgets_with_store 最终执行的 SQL 如下:

INSERT INTO stores_widgets (store_id, widget_id) 
(SELECT #{store.id}, widgets.id 
 FROM widgets
 WHERE widgets.merchant_id = #{store.merchant_id} 
 AND widgets.restricted = FALSE)

因此,如果商家有 100000 个不受限制的小部件,则在一个 INSERT 中创建 100000 个新的 stores_widgets 行,而不是 100000 个不同的 INSERT。

最好我想让 ActiveRecord 构建这样的插入。那可能吗?如果不是,我可以用 ARel 做到这一点吗?如果可能的话,我想避免执行 SQL 字符串来实现这一点,这样我就可以在代码和数据库 SQL 语法之间保持一个级别。

【问题讨论】:

    标签: ruby-on-rails activerecord ruby-on-rails-3.2 arel


    【解决方案1】:

    你可以使用 activerecord-import 实现 AR#import

    activerecord-import 是一个使用 ActiveRecord 批量插入数据的库。

    看看它是如何工作的:

    books = []
    10.times do |i| 
      books << Book.new(:name => "book #{i}")
    end
    Book.import books
    

    参考 - https://github.com/zdennis/activerecord-import

    【讨论】:

    • activerecord-import 看起来很有希望,但看来我必须先将所有 100000 个小部件选择到内存中,然后将模型数组传递给导入才能在我的情况下工作。我怀疑我需要分批执行此操作。这当然不是一个不可行的解决方案,但我更喜欢使用单个 SQL 语句在一个原子操作中执行选择和插入。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2022-12-21
    • 2014-09-07
    • 2017-03-23
    • 2018-05-08
    • 2021-01-19
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多