我需要根据我的VPC控制器中几个表的params搜索找到多列的平均值,但是我在查看视图中的平均结果时遇到问题,而且从数据库中读取的搜索速度很慢。想知道下面要做的最佳方法。是否最好在模型中进行平均值? (不知道如何做到这一点)
模型
class Vpc < ActiveRecord::Base
has_many :results
end
class Result < ActiveRecord::Base
attr_accessible :trial_id, :variety_id, :year, :lint, :turnout, :length_decimal, :length_imperial, :strength, :uniformity, :micronaire, :manual_class
belongs_to :trial, :primary_key => 'trial_id'
belongs_to :variety, :primary_key => 'variety_id'
belongs_to :vpc
has_many :sites, :through => :trial
has_many :growers, :through => :trial
has_many :regions, :through => :sites
end
控制器
class VpcController < ApplicationController
add_breadcrumb "Home", :root_url
add_breadcrumb "Variety Performance Comparison", :vpc_index_path
def index
all = Result.select(:variety_id)
@variety = Variety.where(:variety_id => all).order('variety_name DESC')
@years = Result.select('DISTINCT year')
@regions = Region.all
@irrigations = Trial.select('DISTINCT irrigated').order('irrigated ASC')
end
def search
if params[:variety_one] != params[:variety_two]
@comparison = Result.group('trials.trial_id').having('COUNT(*) = 2').where(variety_id: [params[:variety_one], params[:variety_two]]).
joins(:trial).where('trials.irrigated' => params[:irrigated], 'year' => params[:year]).joins(:regions).where('sites.region_id' => params[:regions])
@vone = @comparison.where('variety_id = ?', params[:variety_one]).select('avg(lint) AS lintone')
@vtwo = @comparison.where('variety_id = ?', params[:variety_two]).select('avg(lint) as linttwo')
@count = @comparison.count('DISTINCT results.trial_id')
@years = @comparison.where('results.year' => params[:year]).select('DISTINCT results.year')
@region = @comparison.where('sites.region_id' => params[:regions]).joins(:regions).group('regions.region_id').select("DISTINCT regions.name")
else
redirect_to vpc_index_url, notice: "Can't compare the same variety"
end
@variety_one = Variety.where('variety_id = ?', params[:variety_one]).group('variety_name')
@variety_two = Variety.where('variety_id = ?', params[:variety_two]).group('variety_name')
add_breadcrumb "Results"
end
end
查看结果
<h2>VPC</h2>
<p>We found <%= @count.count %> trials that matched your options, spanning <%= @years.length %> years (<%= @years.map{|y| y.year}.join(", ") %>) and <%= @region.length %> regions (<%= @region.map{|r| r.trial.site.region.name}.join(", ") %>).</p>
<table class="table">
<th></th>
<% @variety_one.each do |v| %>
<th><%= v.variety_name %></th>
<% end %>
<% @variety_two.each do |v| %>
<th><%= v.variety_name %></th>
<% end %>
<th>Difference</th>
<tr>
<td>Yield (bales/ha)</td>
<td><%= "%.2f" % (@vone.lintone/227) unless @vone.blank? %></td>
<td><%= "%.2f" % (@vtwo.lintwo/227) unless @vtwo.blank? %></td>
<td><%= "%.2f" % ((@vone.lintone/227) - (@vtwo.lintwo/227)) unless @lintone.blank? %></td>
</tr>
</tr>
</table>
<hr>
<div class="accordion" id="accordion2">
<div class="accordion-group">
<div class="accordion-heading">
<a class="accordion-toggle" data-toggle="collapse" data-parent="#accordion2" href="#collapseOne">
<b>Overview of results</b> <span class="pull-right"><i class="icon-chevron-down"></i></span>
</a>
</div>
<div id="collapseOne" class="accordion-body collapse">
<div class="accordion-inner">
<table class="table">
<th>Year</th>
<th>Site</th>
<th>Region</th>
<th>Grower</th>
<% @comparison.each do |v| %>
<tr>
<td><%= link_to v.trial.year, trial_trials_path(trial_id: v.trial_id) %></td>
<td><%= link_to v.trial.site.site_name, trial_trials_path(trial_id: v.trial_id) unless v.trial.site.blank? %></td>
<td><%= link_to v.trial.site.region.name, trial_trials_path(trial_id: v.trial_id) unless v.trial.site.blank? %></td>
<td><%= link_to v.trial.grower.full_name, trial_trials_path(trial_id: v.trial_id) unless v.trial.grower.blank? %></td>
</tr>
<% end %>
</table>
</div>
</div>
</div>
SQL错误
Mysql2::Error: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'AS lintone) AS count_avg_lint_as_lintone, avg(lint) AS lintone, trials.trial_id ' at line 1: SELECT COUNT(avg(lint) AS lintone) AS count_avg_lint_as_lintone, avg(lint) AS lintone, trials.trial_id AS trials_trial_id FROM `results` INNER JOIN `trials` ON `trials`.`trial_id` = `results`.`trial_id` INNER JOIN `trials` `trials_results_join` ON `trials_results_join`.`trial_id` = `results`.`trial_id` INNER JOIN `sites` ON `sites`.`site_id` = `trials_results_join`.`site_id` INNER JOIN `regions` ON `regions`.`region_id` = `sites`.`region_id` WHERE `results`.`variety_id` IN (2300, 2255) AND `trials`.`irrigated` IN (0, 1, 2) AND `results`.`year` IN (2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013) AND `sites`.`region_id` IN (1, 2, 3, 4, 5, 6, 7, 8) AND (variety_id = '2300') GROUP BY trials.trial_id HAVING COUNT(*) = 2
答案 0 :(得分:2)
看着你庞大的控制器,我建议如下:
@comparison = Result.group('trials.trial_id').having('COUNT(*) = 2').where(variety_id: [params[:variety_one], params[:variety_two]]).
joins(:trial).where('trials.irrigated' => params[:irrigated], 'year' => params[:year]).joins(:regions).where('sites.region_id' => params[:regions])
@count = @comparison.count('DISTINCT results.trial_id')
@years = @comparison.where('results.year' => params[:year]).select('DISTINCT results.year')
@region = @comparison.where('sites.region_id' => params[:regions]).joins(:regions).group('regions.region_id').select("DISTINCT regions.name")
保持该块相同,但创建一个迁移以添加索引以提高性能。
你不应该多次调用平均值,而是选择你想要的值
@vone = @comparison.where('variety_id = ?', params[:variety_one]).select(avg(lint) as lint, avg...
@vtwo = @comparison.where('variety_id = ?', params[:variety_two]).select(avg(lint) as lint, avg...)
现在,在您的视图中,您可以获得所需的属性。
之后,查看日志以查看是否有任何可以减少的N + 1。