问题
I want to add new column sum(time_entries.hours)
to sql select
I'm querying entries like this:
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"
)
It generates this select:
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
I tried insert :select=>"*, sum(time_entries.hours)"
into hash parameter to all
method, but there is no effect.
How can I add new column to this select? Also I need preserve all current columns, since they are used in filters. Is there any way without specifying all columns by hands?
UPDATE: Ruby 1.9.3 Rails 3.2.13
回答1:
The table names look like from Redmine. I actually ran into a similar problem recently. What I found was that the selected colums stem from the visible scope. I could not pin down why exactly but working without it, the 'select' option worked as intended.
Using
Issue.select("#{Issue.table_name}.*, sum(#{TimeEntries.table_name}.hours AS total_hours").where("#{your_conditions}").group(:id).all
should give you the data you want. The additional column can be accessed directly as an Issue attribute:
Issue.total_hours
Edit:
If it's not possible to select all Issue fields (for creating the full Issue objects) and the sum at the same time, you need to use a second statement after getting the issues you want.
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
Alternatively you can use the included convenience functions in Redmines Issue class. Use this to make the Software do the work for you:
i = Issue.includes(:time_entries).find(1)
i.total_spent_hours
The include makes sure that the calculation doesn't hit the database a second time because all related associations are already loaded.
回答2:
Bit old but something like this should work. (In Rails 5 ish)
issues = Issue. ...
issues.select(
issues.arel.projections,
TimeEntry.arel_table[:hours].sum
)
来源:https://stackoverflow.com/questions/18750196/rails-active-record-add-extra-select-column-to-findall