6

私は3つのモデルを持っています:

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_eventsを作成しました。レコードは一度に1つずつ作成され、それぞれ2つの挿入ステートメントを含む複数のクエリが発生するため、これは非常に非効率的です。

次のような単一の挿入クエリを使用したいと思います。

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

次に、CouponEventモデルの2番目の挿入クエリを作成する必要がありますが、返されたcoupon_idのリストが必要です。挿入時にIDを取得するための組み込みメソッドはありますか?

4

5 に答える 5

3

現時点では、最善の(ただし理想的ではない)ソリューションは、「activerecord-import」を使用して一括インポートすることです。残念ながら、そのgemは挿入されたIDを返さないため、IDを取得するには、向きを変えてクエリを実行する必要があります。つまり、イベントモデルを一括挿入し、データベースにクエリを実行して、すべてをメモリに戻します。これでイベントIDができたので、クーポンを作成して一括挿入できます。CouponEventsの泡を繰り返し洗い流します。

イベントごとの1回のラウンドトリップと比較して、CouponとCouponEvent-おそらく数千行のファイルの場合は数千回のラウンドトリップ-モデルごとに2回のラウンドトリップしか実行していません-1つはイベントを挿入し、もう1つはIDを使用してイベントをフェッチします、同上クーポンとクーポンイベント-合計6往復。

于 2013-07-03T14:10:55.943 に答える
2

実際、このcoludが機能するかどうかはわかりませんが(挿入クエリが1つ作成される場合)、#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

最後の「Returning」句が必要なので、挿入されたIDと挿入された行のコードをフェッチできます。結果セットをマップする必要があります。

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

SQLには、挿入された行の列を返す標準的な方法はありません。「RETURNING」句はPostgreSQLでのみ機能するため、別のデータベースを使用する場合は、ドキュメントを確認するか、行を1つずつ挿入する必要があります。

connection.insertActiveRecordでは、すべての行ではなく、挿入された1つの行のIDのみが返されるため、を使用することもできません。

于 2012-12-05T08:25:52.763 に答える
1

import_idこれを行う方法は、一意の値を持つレコードを挿入することです。手順は次のとおりです。

  1. import_idテーブルに列を追加します。ランダムIDを生成する方法によって、INTまたはそれに依存する可能性があります。VARCHAR

  2. 最初の前にINSERT、ランダムIDを生成します。

  3. 各行INSERTに同じものを使用して、最初の複数値を実行します。import_id

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

  5. INSERT返されたIDを使用して2番目の複数値を生成します。

于 2013-11-21T19:26:33.310 に答える
0

connection.insertは1つの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が順番に生成されます。

すなわち

    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 に答える