【发布时间】: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