【问题标题】:Rails 4 / postgresql - insert data on a table based on another table data (after_create)Rails 4 / postgresql - 根据另一个表数据在一个表上插入数据(after_create)
【发布时间】:2015-09-05 03:26:54
【问题描述】:

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

Deal 和 DealPrize 有一个属于/has_many 关系:一个 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 和使用“事务”)。确实,最有效的方法(选项 3:'A single mass insert')在 piostgresql 中不容易获得(这个家伙给出了 SQL 的例子),而且对于 mee a 来说太难了(它涉及一些 COPY 命令......)。

所以这是我优化之前的代码(它有效)

models/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

这是我尝试过的:

models/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 ‘dealprize’,INSERT INTO ‘DealPrize’ 也不起作用。

如何用 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

【问题讨论】:

  • 不需要使用self。
  • INSERT INTO deal_prizes .... #should 工作。尝试不带任何反引号

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


【解决方案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

【讨论】:

  • 嗨,现在就试试,抱歉耽搁了
【解决方案2】:

做一些表演怎么样。您可以只进行一次长查询,而不是执行 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)"

【讨论】:

  • 我遇到了一个问题,因为我需要添加另外两个属性和一个错误 => 查看我的问题编辑
  • 请在 rails 插入内容时发布 rails-log-sql
  • 把它放在我的编辑器里
  • 你的 sql 完全关闭了。在我的 sql 中没有关于时间戳的内容。我还要求您将 rails-sql 放入 insert,即 Prizes.create,以查看 rails sql 的样子
  • 如果我不添加 created_at 和 updated_at 我收到此错误“错误:“created_at”列中的空值违反非空约束,因此我需要添加它们,就像您在我的问题中看到的一样编辑
猜你喜欢
  • 1970-01-01
  • 2014-10-11
  • 1970-01-01
  • 1970-01-01
  • 2019-01-10
  • 2013-10-08
  • 2013-04-25
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多