活动记录和SQL的问题

时间:2010-10-06 08:45:07

标签: sql ruby-on-rails activerecord

我有一点问题:我无法在AR中编写sql-query。

所以,我有ProjectTask个型号,Project has_many TasksTask有aasm-field(即“status”;但无关紧要,我可以是简单的int或字符串字段)。

所以,我想在我的项目索引页面列表中列出所有(最后)项目,并且我希望每个项目都计算它是活动的,待定的和已解决的(例如)任务。

像这样,看看:

  • 第一个项目(1个有效,2个未决, 10解决)
  • 第二个项目(4 有效,2待决,2已解决)

因此,我确定可以使用@projects = Project.all,然后在视图中执行此操作:

- @projects.each do |project| 
  = project.title
  = project.tasks(:conditions => {:status => "active"}).count #sure it should be in model, just for example
  = project.tasks(:conditions => {:status => "pending"}).count
  # ...
- end

这很好,但是生成1 + N * 3(针对3个任务状态)查询,我想1.问题很简单:how?

4 个答案:

答案 0 :(得分:0)

我建议在项目模型中使用计数器缓存,以防止需要在索引页面的每个显示上重新计算所有任务 - 拥有active_count,pending_count和resolved_count,并在任务更改状态时更新它们。

如果您只想修改现有代码,请尝试:

project.tasks.count(:conditions => "status = 'active'")

您还可以在任务模型中添加一个范围,使您可以执行以下操作:

project.tasks.active.count

修改

好的,所以我半睡半醒 - 从你的问题中得到了错误的印象:/

是的,您可以在一个查询中执行此操作 - 使用find_by_sql来获取项目以及任务的分组计数。您将能够在结果项目数组中访问组计数。

答案 1 :(得分:0)

您可以使用分组和计数进行查找。类似的东西:

status_counts = project.tasks.find(:all, 
                                   :group => 'status', 
                                   :select => 'status, count(*) as how_many')

这会返回一个Task类似对象的列表,其中包含statushow_many属性,您可以使用这些属性来提供摘要。 E.g。

<%= status_counts.map { |sc| "#{sc.how_many} #{sc.status} }.to_sentence %>

答案 2 :(得分:0)

也许你可以在你的项目控制器中:

  1. 获取所有项目:Project.all
  2. 获取所有任务:Task.all
  3. 然后,创建一个类似

    的哈希
    @statuses = Hash.new
    @tasks.each do |t|
      @statuses[:t.project_id][:t.status] += 1
    end
    

    然后在您的视图中使用它:

    First project (<%= @statuses[:@project.object_id][:active] %> active)
    

    这不是完美的解决方案,但它很容易实现,只使用两个(大)查询。当然,这会每次都重新创建一个哈希,所以你可能想要查看数据库索引或缓存系统。

    此外,named scopes会很有趣,例如Task.active

答案 3 :(得分:0)

所以,正确的答案是:

Projects.all(:joins  => :tasks, 
             :select => 'projects.*, 
                         sum(tasks.status="pending") as pending_count, 
                         sum(tasks.status = "accepted") as accepted_count, 
                         sum(tasks.status = "rejected") as rejected_count', 
             :group  => 'projects.id')