我有一个名为acts
的表,我想运行一个查询,将整个行动值累计一整周。我想确保查询总是为一周中的每一天返回一行,即使当天没有记录。现在我这样做:
def self.this_week_totals
sunday = Time.now.beginning_of_week(:sunday).strftime("%Y-%m-%d")
connection.select_values(<<-EOQ)
SELECT COALESCE(SUM(end_time - start_time), '0:00:00') AS total_time
FROM generate_series(0, 6) AS s(t)
LEFT JOIN acts
ON acts.day = '#{sunday}'::date + s.t
WHERE deleted_at IS NULL
GROUP BY s.t
ORDER BY s.t
EOQ
end
我有什么方法可以将它作为Act类的命名范围,以便它可以与其他条件结合使用,例如以client_id
过滤使徒行传?由于acts
不在我的FROM
中,而是LEFT JOIN
的一部分,我猜不会,但也许有人知道某种方式。
编辑:只是为了澄清,目标是这个方法总是返回7个Act对象,无论数据库中有什么。
答案 0 :(得分:2)
如果您希望查询对象是可链接的,则它必须是ActiveRelation对象
where
,select
,order
和其他Arel对象返回可链接的ActiveRelation对象,因此如果以下工作可以链接返回的查询对象
注意在rails 3及以上版本中,返回ActiveRelation的类方法与作用域基本相同,它们都是可链接的查询对象
class Act
def self.this_week_totals
sunday = Time.now.beginning_of_week(:sunday).strftime("%Y-%m-%d")
select("COALESCE(SUM(end_time - start_time), '0:00:00') AS total_time")
.from("generate_series(0, 6) AS s(t)")
.joins("LEFT JOIN acts ON acts.day = '#{sunday}'::date + s.t")
.where("deleted_at IS NULL")
.group("s.t")
.order("s.t")
end
# ...
end
client_id = params[:client_id]
Act.this_week_totals.where("client_id = ?", client_id)
http://api.rubyonrails.org/classes/ActiveRecord/QueryMethods.html#method-i-from
答案 1 :(得分:1)
虽然我真的认为我可以使用@ house9的解决方案,但我认为没有办法避免至少在其中一个目标上妥协:
clients
表。以下是我实际使用的part-SQL / part-Ruby解决方案,遗憾地放弃了上面的#2点,并且还返回了元组而不是Acts:
def self.this_week(wk=0)
sunday = Time.now.beginning_of_week(:sunday)
sunday += wk.weeks
not_deleted.where("day BETWEEN ? AND ?", sunday, sunday + 7.days)
end
scope :select_sum_total_hours,
select("EXTRACT(EPOCH FROM COALESCE(SUM(end_time - start_time), '0:00:00'))/3600 AS total_hours")
scope :select_sum_total_fees,
joins(:client).
select("SUM(COALESCE(clients.rate, 0) * EXTRACT(EPOCH FROM COALESCE(end_time - start_time, '0:00:00'))/3600) AS total_fees")
def self.this_week_totals_by_day(wk=0)
totals = Hash[
this_week(wk)
.select("EXTRACT(DAY FROM day) AS just_day")
.select_sum_total_hours
.select_sum_total_fees
.group("day")
.order("day")
.map{|act| [act.just_day, [act.total_hours.to_f, act.total_fees.to_money]]}
]
sunday = Time.now.beginning_of_week(:sunday)
sunday += wk.weeks
(0..6).map do |x|
totals[(sunday + x.days).strftime("%d")] || [0, 0.to_money]
end
end
这可能会有点干扰,如果有一个月只有不到7天,它会产生错误,但希望它能显示我正在做的事情。 this_week
,select_sum_total_hours
和select_sum_total_fees
的范围在其他地方使用,因此我想将它们移到范围中,而不是在几个大的原始SQL字符串中重复它们。