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

时间:2015-09-01 09:21:09

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

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

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

它的工作原理如下:内部交易,我有一个专栏'奖品编号'我使用了一个after_create,以便amdin创建一个新的交易,应用程序获取这个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),如this guy for 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'DealDePrize'它也不起作用。

如何使用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_prizes不同的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

2 个答案:

答案 0 :(得分:1)

好像你的代码中有拼写错误。连接应为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

答案 1 :(得分:0)

如何制作一些表演。而不是执行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)"