【问题标题】:Need help turning a SQL query into an ActiveRecord query需要帮助将 SQL 查询转换为 ActiveRecord 查询
【发布时间】:2011-09-07 14:34:44
【问题描述】:

我有以下 SQL 代码:

SELECT u.full_name, pu.task_name, sum(hours) 
FROM efforts
INNER JOIN project_tasks pu ON efforts.project_task_id = pu.id   
INNER JOIN users u ON efforts.user_id = u.id 
GROUP BY user_id, task_name

输出所有用户、他们的任务和他们的时间。我现在要做的是将其转换为 Rails 的 ActiveRecord 查询。

我试图让它看起来类似于我在下面所做的,但似乎无法让我的逻辑正确。

    Project.all.each do |project|
      projdata = { 'name' => project.project_name.to_s,
                  'values' => [] }

    ['Pre-Sales','Project','Fault Fixing','Support'].each do |taskname|

     record = Effort.sum( :hours,
                          :joins => :project_task,
                           :conditions => { "project_tasks.project_id" => project.id,
                                         "project_tasks.task_name" => taskname } )             
        projdata[ 'values' ].push( record )
      end

      @data.push( projdata )
    end
  end
end 

添加图片链接

Link to image

该链接说明了一个图表。我需要做的是将我的 SQL 语句转换为一个 activeRecord 查询,它将像我提供的其他图表一样显示它。

【问题讨论】:

  • 我想把上面的 SQL 语句变成 RoR,这样当我把它实现成 highcharts 时,它会显示所有用户的任务和时间
  • 为此,您需要展示您的 ActiveRecord 模型,因为从中生成了 SQL。但真正的问题是什么?究竟是什么问题?你需要更清楚一点..
  • 上面的 SQL 工作......我需要让它“Ruby-fied” 我需要它看起来像上面变量“record”的代码。例如Effort.sum...等
  • 您似乎试图获取每个用户在每项任务上花费的时间总和,对吗?因为它不是很清楚,我什至对你的 SQL 工作感到惊讶(你应该有类似 SUM(小时)的东西)。此外,您的表名不遵循 AR 约定,因此很难遵循
  • @m_x 你的权利,这就是我想要做的,对不起,它不是很清楚,我只是认为考虑到它在 SQL 中工作它会很容易转换......而且我确实有 SUM(小时)但忘了把它放进去..

标签: mysql sql ruby-on-rails ruby-on-rails-3


【解决方案1】:
SELECT u.full_name, pu.task_name, hours 
FROM efforts
INNER JOIN project_tasks pu ON efforts.project_task_id = pu.id   
INNER JOIN users u ON efforts.user_id = u.id 
GROUP BY user_id, task_name

Effort.find(:all, :select => "users.full_name, project_tasks.task_name, hours", :joins => [:user, :project_task], :group => "users.user_id, project_tasks.task_name")

但是,我有一个疑问,如何在不将“小时”字段添加到分组部分的情况下获得它。所以,更好的是,您也可以在分组部分添加时间。

但是,您应该在以下文件中进行一些额外的更改

供应商/插件/expandjoinquery/init.rb'

class ActiveRecord::Base
  class << self
    private
    def add_joins!(sql, options, scope = :auto)
      scope = scope(:find) if :auto == scope
      join = (scope && scope[:joins]) || options[:joins]
      sql << " #{expand_join_query(join)} " if join
    end

    def expand_join_query(*joins)
      joins.flatten.map{|join|
        case join
        when Symbol
          ref = reflections[join] or
            raise ActiveRecord::ActiveRecordError, "Could not find the source association :#{join} in model #{self}"
          case ref.macro
          when :belongs_to
            "INNER JOIN %s ON %s.%s = %s.%s" % [ref.table_name, ref.table_name, primary_key, table_name, ref.primary_key_name]
          else
            "INNER JOIN %s ON %s.%s = %s.%s" % [ref.table_name, ref.table_name, ref.primary_key_name, table_name, primary_key]
          end
        else
          join.to_s
        end
      }.join(" ")
    end
  end
end

参考:http://snippets.dzone.com/posts/show/2119

我的建议是,为什么要使用带有关联名称的预加载?

【讨论】:

  • 谢谢,但我需要类似这种格式的,我已经编辑了你的回复
  • 看来@Djj 想要一个小时的总和。我已经在尝试完全使用 group() 和 average() 时遇到了麻烦,最终使用了select("average(model.field), name").group("name") 之类的东西,效果很好。不是更简单吗?
【解决方案2】:

试试这个:

Effort.select(
   "users.full_name        full_name, 
    project_tasks.task_name       task_name, 
    SUM(efforts.hours) total_hours").
  joins(:project_task, :user).
  group("users.user_id, users.full_name, project_tasks.task_name").map do |e|
  puts e.full_name, e.task_name, e.total_hours
end 

【讨论】:

    【解决方案3】:

    尝试类似:

    Effort.joins(:project_tasks, :user).select("sum(hours) as total_hours, users.full_name, project_tasks.task_name").group("users.user_id, project_tasks.task_name")
    

    【讨论】:

    • record = Effort.sum( :hours, :joins =&gt; :project_task, :conditions =&gt; { "project_tasks.project_id" =&gt; project.id, "project_tasks.task_name" =&gt; taskname } ) projdata[ 'values' ].push( record ) end 我需要它看起来与此类似,以便我可以将所有数据推回数组
    • 那么您可以尝试在链的末尾添加类似.collect(&amp;:hours) 的内容(请参阅ruby-doc.org/core/classes/Array.html#M000247 fo collect() 用法)
    • 不确定它是否有效,但您可能想试试这个:Effort.sum(:hours, :group => [:project_task_id, :user_id], :joins => [:project_task, :用户])
    猜你喜欢
    • 1970-01-01
    • 2020-07-28
    • 1970-01-01
    • 1970-01-01
    • 2020-05-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多