6

我有三个模型:

class Coupon < ActiveRecord::Base
  belongs_to :event
  has_many :coupon_events, :dependent => :destroy
  has_many :events, :through => :coupon_events
end 

class Event < ActiveRecord::Base
  belongs_to :event
  has_many :coupon_events, :dependent => :destroy
  has_many :coupons, :through => :coupon_events
end

class CouponEvent < ActiveRecord::Base
  belongs_to :coupon
  belongs_to :event
end

我通读了一个 CSV 文件以创建优惠券和优惠券事件。这是非常低效的,因为一次创建一个记录并导致多个查询,每个查询都包括两个插入语句。

我想使用这样的单个插入查询:

coupon_string = " ('abc','AAA'), ('123','BBB')"
Coupon.connection.insert("INSERT INTO coupons (code, name) VALUES"+coupon_string)

然后我需要为 CouponEvent 模型创建第二个插入查询,但我需要返回的 coupon_ids 的列表。是否有内置方法可以在插入时检索 ID?

4

5 回答 5

3

目前,最好(但不理想)的解决方案是使用"activerecord-import"进行批量导入。不幸的是,该 gem 不会返回插入的 id,因此您必须转身查询才能获取 id。也就是说,您将批量插入事件模型,查询数据库以将它们全部恢复到内存中。现在您有了事件 ID,因此您可以创建优惠券并批量插入它们。为 CouponEvents 重复冲洗泡沫。

与每个事件、Coupon 和 CouponEvent 一次往返相比 - 对于具有数千行的文件可能有数千次往返 - 每个模型只执行 2 次往返 - 一个用于插入事件,一个用于使用 id 取回事件,同上 Coupon 和 CouponEvent - 共 6 次往返。

于 2013-07-03T14:10:55.943 回答
2

实际上我不确定这个 colud 是否有效(如果它创建一个插入查询),但您可以尝试使用#create带有参数数组的方法:

new_coupons = Coupon.create([
  { :code => "abc", :name => "AAA" },
  { :code => "123", :name => "BBB" }
])

CouponEvent.create([
  { :enevt_id => ..., coupon_id: ...},
  ...
])

要为 CouponEvent 创建参数列表,您需要将返回的 new_coupons 集合映射到 id 并根据优惠券代码/名称添加 event_id(取决于它存储在 CVS 文件中的方式)。

更新

我自己检查过,如果第一个解决方案不起作用(我的代码中没有简单的模型没有唯一性约束,所以我没有检查过),并且你使用 PostgreSQL,你总是可以做这样的事情:

res = Coupon.connection.execute(<<-EOSQL)
  INSERT INTO coupons (code, name)
  VALUES #{values}
  RETURNING id, code
EOSQL

您需要最后一个“返回”子句,因此您可以获取插入的 id 以及插入行的代码。您需要映射结果集:

res.map {|row|
  { :coupon_id => row["id"],
    :event_id => events.find { |e| e.coupon_code == row["code"] }
  }
}

SQL 中没有标准的方法来返回插入行的列,“RETURNING”子句仅在 PostgreSQL 中有效,因此如果您使用不同的数据库,则需要检查文档或一一插入行。

您也不能使用connection.insert,因为在 ActiveRecord 中它只返回一个插入行的 id,而不是所有行。

于 2012-12-05T08:25:52.763 回答
1

这样做的方法是插入具有唯一import_id值的记录。步骤是:

  1. 向表中添加一import_id列。可能是INTVARCHAR取决于您如何生成随机 ID。

  2. 在第一个之前INSERT,生成一个随机ID。

  3. 执行第一个 multi-value ,对每一行INSERT使用相同的值。import_id

  4. SELECT id FROM first_table WHERE import_id=<the random import ID>

  5. INSERT使用返回的 ID生成第二个多值。

于 2013-11-21T19:26:33.310 回答
0

connection.insert 只返回一个id,公用表表达式对我有用

    insert_sql = <<-SQL
      WITH inserted_ids AS (
        INSERT INTO clients (email, name) VALUES #{array.join(', ')}
        RETURNING id
      )
      SELECT * FROM inserted_ids
    SQL
    result = ActiveRecord::Base.connection.execute(insert_sql)
于 2016-07-29T01:20:49.647 回答
-2

如果您使用的是 mysql 并且没有在另一个脚本/进程中插入更多行,则可以使用 last_insert_id() 获取插入的第一行的 id

    first_id = ActiveRecord::Base.connection.execute("select last_insert_id()").first[0]

然后依次生成其他记录的id。

IE

    data = %w(one two three)
    to_insert = "('" + data.join("'), ('") + "')"
    Model.connection.insert("INSERT INTO models(name) VALUES #{to_insert}")
    first_id = ActiveRecord::Base.connection.execute("select last_insert_id()").first[0].to_i
    hash = {}
    data.each_with_index {|d, i| hash[first_id + i] = d}
于 2012-12-05T08:51:34.053 回答