我有一个评估模型。评价有很多分数。每当创建新评估时,都会为需要评估的每个用户创建评分记录(请参阅下面我正在使用的当前方法。)因此,例如,可以一次创建40个评分记录。然后,评估所有者使用用户的分数更新每个分数记录。
我正在寻找使用原始SQL,因为每个插入都是它自己的事务并且速度很慢。
我想使用原始SQL将以下内容转换为批量插入语句:
def build_evaluation_score_items
self.job.active_employees.each do |employee|
employee_score = self.scores.build
employee_score.user_id = employee.id
employee_score.save
end
end
有关如何做到这一点的任何想法?我已经尝试过改编Chris Heald的Coffee Powered网站的代码示例,但是没有骰子。
感谢愿意提供帮助的人!
编辑1
我忽略了提到当前的方法被包装在一个事务中。
所以,基本上,我试图将它添加到代码块中,所以所有内容都插入到一个语句中(**这段代码snippit来自Chris Heald的Coffee Powered网站,讨论了这个主题。我会问那个问题,但是帖子是> 3岁。):
inserts = []
TIMES.times do
inserts.push "(3.0, '2009-01-23 20:21:13', 2, 1)"
end
sql = "INSERT INTO user_node_scores (`score`, `updated_at`, `node_id`, `user_id`)VALUES #{inserts.join(", ")}"
我很乐意展示一些不起作用的代码......
再次感谢!
好吧,我拼凑了一些类似于上面代码的东西,但我在('evaluation_id'部分周围得到一个SQL语句无效错误。有什么想法吗?
def build_evaluation_score_items
inserts = []
self.job.active_employees.each do |employee|
inserts.push "(#{self.id}, #{employee.id}, #{Time.now}, #{Time.now})"
end
sql = "INSERT INTO scores ('evaluation_id', `user_id`, 'created_at', `updated_at`)VALUES #{inserts.join(", ")}"
ActiveRecord::Base.connection.execute(sql)
end
知道上面的SQL代码是什么导致错误?
答案 0 :(得分:17)
好吧,经过多次反复试验,这是最后的答案。很酷的是,所有记录都是通过一个语句插入的。当然,跳过验证(因此如果您在创建时需要模型验证,这将不合适)但在我的情况下,这不是必要的,因为我所做的只是为每个员工的评估设置得分记录。当然,当工作领导者更新员工的评估分数时,验证会按预期工作。
def build_evaluation_score_items
inserts = []
time = Time.now.to_s(:db)
self.job.active_employees.each do |employee|
inserts.push "(#{self.id}, #{employee.id}, '#{time}')"
end
sql = "INSERT INTO scores (evaluation_id, user_id, created_at) VALUES #{inserts.join(", ")}"
ActiveRecord::Base.connection.execute(sql)
end
答案 1 :(得分:7)
我建议使用activerecord-import gem,而不是直接构建SQL(并打开SQL注入和其他问题)。除其他策略外,它还可以发出多行INSERT
命令。
然后您可以编写如下内容:
def build_evaluation_score_items
new_scores = job.active_employees.map do |employee|
scores.build(:user_id => employee.id)
end
Score.import new_scores
end
答案 2 :(得分:5)
我认为您正在寻找的是:
def build_evaluation_score_items
ActiveRecord::Base.transaction do
self.job.active_employees.each do |employee|
employee_score = self.scores.build
employee_score.user_id = employee.id
employee_score.save
end
end
end
所有子事务都会自动“推送”到父事务。这样可以防止这么多交易的开销,并且可以提高性能。
您可以阅读有关ActiveRecord交易here的更多信息。
<强>更新强>
对不起,我误会了。为后代保留上述答案。试试这个:
def build_evaluation_score_items
raw_sql = "INSERT INTO your_table ('user_id', 'something_else') VALUES "
insert_values = "('%s', '%s'),"
self.job.active_employees.each do |employee|
raw_sql += insert_values % employee.id, "something else"
end
ActiveRecord::Base.connection.execute raw_sql
end