Rails 4 / postgresql – 根据另一个表数据在表上插入数据(after_create)

在创建模型交易时,我使用after_create在DealPrize表上创建奖品。

Deal和DealPrize属于/ has_many关系:a Deal有许多Deal奖品,Dealprize属于Deal。

它的工作方式如下:在Deal中,我有一个列’prize-number’,我使用了after_create,以便amdin创建一个新的交易evetytime,应用程序获取此prize_number列,并创建此批量的奖品(插入尽可能多的行必要时)在DealPrize表中。

出于性能考虑,奖品数量可以> 500,000并且为了优化INSERT。

我找到了https://www.coffeepowered.net/2009/01/23/mass-inserting-data-in-rails-without-killing-your-performance/ :我选择了选项2(原始SQL和usi_ng’事务) “)。 事实上,最有效的方式(选项3:’单个质量插入’)在piostgresql中不容易获得(这个人提供了SQL的exmaples)并且对于mee来说太难了(它涉及一些COPY命令……)。

所以这是我的代码优化之前(它工作)

车型/ deals.rb

after_create :create_deal_prizes def create_deal_prizes self.prizes_number.times do prizes = DealPrize.create(:deal_id => self.id, :admin_user_id => self.admin_user_id) prizes.save end end 

所以我没有在PostgreSQL中应用选项2(带有事务的原始SQL),就像这个用于SQL的人一样

这是’我试过的:

车型/ deals.rb

 after_create :create_deal_prizes def create_deal_prizes Deal.transaction do self.prizes_number.times do |i| DealPrize.connection.execute "INSERT INTO 'deal_prizes' (deal_id) values (self.deal.id)" end end end 

但它失败了,我收到错误:

 ERROR: relation "'deal_prizes'" does not exist LINE 1: INSERT INTO 'click_win_throbbers' (deal_id) 

顺便说一句,我也试过INSERT INTO’dealprizes’,INSERT INTO’DeallyPrize’它也不起作用。

如何用PostgreSQL做到这一点?

谢谢你的帮助

编辑我试过

  def create_deal_prizes Deal.transaction do values = (0..prize_number).to_a.map{|x| "(#{x}),"}.join.chomp(",") ActiveRecord::Base.connection.execute "INSERT INTO deal_prizes (deal_id, created_at, updated_at) values ( (#{values}), ('2009-01-23 20:21:13'), ('2009-01-23 20:21:13') )" end end 

我收到此错误:

 ERROR: column "deal_id" is of type integer but expression is of type record PG::SyntaxError - ERROR: INSERT has more expressions than target columns LINE 1: ...id, created_at, updated_at) values ( (0),(1),(2),(3),(4),(5).. 

除了必须放入新的deal_prizes的每一行的deal_id是相同的:它总是这个单一游戏的id:我不会每一行deal_priz都有不同的deal_id(就像这里(1),(2) )…

这是原始SQL

 SELECT 1 AS one FROM "deals" INNER JOIN "friendly_id_slugs" ON "friendly_id_slugs"."sluggable_id" = "deals"."id" AND "friendly_id_slugs"."sluggable_type" = $1 WHERE ("deals"."id" IS NOT NULL) AND ("friendly_id_slugs"."sluggable_type" = 'Deal' AND "friendly_id_slugs"."slug" = 'zazzaza') LIMIT 1 [["sluggable_type", "Deal"]] SQL (0.5ms) INSERT INTO "deals" ("deal_main_goal", "deal_population_target_age", "deal_population_target_egroup", "deal_campaign_code", "country", "title", "description", "twitter_msg", "image_url", "deal_project_management_url", "client_contact_point_name", "client_contact_point_profile_url", "hp_image_alt", "rules_url", "deal_population_target_gender", "contact_for_prizes_full_name", "contact_for_prizes_email", "contact_for_prizes_how_to_contact_details", "contact_for_prizes_crm_profile_url", "click_to_win_throbber_per_deal_qty", "admin_user_id", "slug", "created_at", "updated_at") VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15, $16, $17, $18, $19, $20, $21, $22, $23, $24) RETURNING "id" [["deal_main_goal", "{}"], ["deal_population_target_age", "{}"], ["deal_population_target_egroup", "{}"], ["deal_campaign_code", ""], ["country", "Armenia"], ["title", "zazzaza"], ["description", ""], ["twitter_msg", ""], ["image_url", ""], ["deal_project_management_url", ""], ["client_contact_point_name", ""], ["client_contact_point_profile_url", ""], ["hp_image_alt", ""], ["rules_url", ""], ["deal_population_target_gender", ""], ["contact_for_prizes_full_name", ""], ["contact_for_prizes_email", ""], ["contact_for_prizes_how_to_contact_details", ""], ["contact_for_prizes_crm_profile_url", ""], ["prize_number", 7], ["admin_user_id", 1], ["slug", "zazzaza"], ["created_at", "2015-09-04 21:21:41.157857"], ["updated_at", "2015-09-04 21:21:41.157857"]] (1.6ms) INSERT INTO deal_prizes (deal_id, created_at, updated_at) values ( ((0),(1),(2),(3),(4),(5),(6),(7)), ('2009-01-23 20:21:13'), ('2009-01-23 20:21:13') ) PG::DatatypeMismatch: ERROR: column "deal_id" is of type integer but expression is of type record LINE 1: ...obbers (deal_id, created_at, updated_at) values ( ((0),(1),(... ^ HINT: You will need to rewrite or cast the expression. : INSERT INTO deal_prizes (deal_id, created_at, updated_at) values ( ((0),(1),(2),(3),(4),(5),(6),(7)), ('2009-01-23 20:21:13'), ('2009-01-23 20:21:13') ) (1.8ms) ROLLBACK Completed 500 Internal Server Error in 605ms PG::DatatypeMismatch - ERROR: column "deal_id" is of type integer but expression is of type record 

好像你的代码中有拼写错误。 连接应该是ActiveRecord::Base.connection但你写了DealPrize.connection.execute

 connection = ActiveRecord::Base.connection connection.execute "sql query" 

尝试更改您的代码

 after_create :create_deal_prizes def create_deal_prizes Deal.transaction do connection = ActiveRecord::Base.connection self.prizes_number.times do |i| connection.execute "INSERT INTO 'deal_prizes' (deal_id) values (self.deal.id)" end end end 

如何做一些表演。 而不是执行n次原始SQL,你可以只进行一次长查询。 感谢@Dipak找到错字

 after_create :create_deal_prizes def create_deal_prizes Deal.transaction do values = (0..prizes_number).to_a.map{|x| "(#{x}),"}.join.chomp(",") ActiveRecord::Base.connection.execute "INSERT INTO deal_prizes (deal_id) values #{values}" end end 

那给了我

 "INSERT INTO deal_prizes (deal_id) values (0),(1),(2),(3),(4),(5),(6),(7),(8),(9),(10),(11),(12),(13),(14),(15),(16),(17),(18),(19),(20),(21),(22),(23),(24),(25),(26),(27),(28),(29),(30),(31),(32),(33),(34),(35),(36),(37),(38),(39),(40),(41),(42),(43),(44),(45),(46),(47),(48),(49),(50)"