【问题标题】:Rails - Active Record: add extra select column to find(:all)Rails - Active Record:向 find(:all) 添加额外的选择列
【发布时间】:2013-09-11 20:02:17
【问题描述】:

我想将新列 sum(time_entries.hours) 添加到 sql select 我正在查询这样的条目:

issues = Issue.visible.where(options[:conditions]).all(
    :include => ([:status, :project, :time_entries] + (options[:include] || [])).uniq,
    :conditions => statement,
    :order => order_option,
    :joins => query_joins(order_option.join(',')),
    :limit => options[:limit],
    :offset => options[:offset],
    :group => "#{Issue.table_name}.id"
)

它生成这个选择:

SELECT
 "issues"."id"                         AS t0_r0,
 ...
 "time_entries"."hours"                AS t3_r4,
 ...
 "versions"."sharing"                  AS t8_r9
FROM "issues"
 LEFT OUTER JOIN "projects" ON "projects"."id" = "issues"."project_id"
 LEFT OUTER JOIN "issue_statuses" ON "issue_statuses"."id" = "issues"."status_id"
 LEFT OUTER JOIN "time_entries" ON "time_entries"."issue_id" = "issues"."id"
 LEFT OUTER JOIN "users" ON "users"."id" = "issues"."assigned_to_id"
 LEFT OUTER JOIN "trackers" ON "trackers"."id" = "issues"."tracker_id"
 LEFT OUTER JOIN "enumerations"
   ON "enumerations"."id" = "issues"."priority_id" AND "enumerations"."type" IN ('IssuePriority')
 LEFT OUTER JOIN "issue_categories" ON "issue_categories"."id" = "issues"."category_id"
 LEFT OUTER JOIN "versions" ON "versions"."id" = "issues"."fixed_version_id"
WHERE "issues"."id" IN (1) AND (projects.status <> 9 AND projects.id IN (SELECT
                                                                       em.project_id
                                                                     FROM enabled_modules em
                                                                     WHERE em.name =     'issue_tracking')) AND
  ((issues.status_id IN (SELECT
                           id
                         FROM issue_statuses
                         WHERE is_closed = 'f')))
GROUP BY issues.id
ORDER BY issues.id
 DESC

我尝试在all方法的哈希参数中插入:select=&gt;"*, sum(time_entries.hours)",但没有效果。

如何向此选择添加新列? 我还需要保留所有当前列,因为它们用于过滤器。 有没有办法不手动指定所有列?

更新: 红宝石 1.9.3 导轨 3.2.13

【问题讨论】:

  • 在您的第一个代码块中,为什么要将新的 arel 查询方法 (where) 与旧的已弃用的魔术查找器混合在一起? .all(:include =&gt; [...])?您应该将其全部更改为使用 arel,因为当您升级 rails 时,您的 .all 方法将停止工作。
  • 嗯,好的,我会解决的。这是 redmine 插件的一部分 - 我正在覆盖控制器操作 - 这部分是从被覆盖的操作中复制粘贴(有一些小的修改)。

标签: ruby-on-rails activerecord rails-activerecord


【解决方案1】:

表名看起来像 Redmine 中的。我最近实际上遇到了类似的问题。我发现选定的列来自可见范围。我无法确定确切的原因,但如果没有它,“选择”选项会按预期工作。

使用

Issue.select("#{Issue.table_name}.*, sum(#{TimeEntries.table_name}.hours AS total_hours").where("#{your_conditions}").group(:id).all

应该给你你想要的数据。附加列可以作为问题属性直接访问:

Issue.total_hours

编辑:

如果无法同时选择所有问题字段(用于创建完整的问题对象)和总和,则需要在获得所需问题后使用第二条语句。

issues = Issue.visible.where("#{issue_conditions}").all
issue_ids = issues.map(&:id)
# if you do not need the issue objects, use .pluck(:id) instead of .all

spent_hours = TimeEntries.select('issue_id, sum(hours)')
                         .where(:issue_id => issue_ids)
                         .where("#{other_time_conditions}")
                         .group(:issue_id).all

或者,您可以使用 Redmines Issue 类中包含的便利功能。使用它使软件为您工作:

i = Issue.includes(:time_entries).find(1)
i.total_spent_hours

包含确保计算不会再次命中数据库,因为所有相关关联都已加载。

【讨论】:

  • 是的,你是对的 - 这是 redmine 插件的一部分。在第一个示例中,您的意思是将all(...) 替换为select(..) 或将此选择添加到all?第二个变体根本不适合我,因为我想在查询中的时间条目记录上使用过滤器(例如计算花费的时间 in_between)
  • 我已经使示例更加具体,只是省略了您的包含、限制和其他特殊条件。就像您对原始帖子的评论所述,您应该使用 AREL 方法来构建您的语句,而不是将其转储到 .all 方法中。另外,我添加了另一个使用两个选择的替代方案。有时,使用更多选择而不是使用多个连接的大选择更容易,而且通常更快。
  • 谢谢,第一个变种正是我所需要的。
  • 在一个查询中肯定有可能,你需要分组!
【解决方案2】:

有点旧,但这样的东西应该可以工作。 (在 Rails 5 中)

issues = Issue. ...

issues.select(
  issues.arel.projections,
  TimeEntry.arel_table[:hours].sum
)

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2011-01-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-11-22
    • 2012-02-23
    • 1970-01-01
    相关资源
    最近更新 更多