假设我尝试计算一段时间内每个部门的事故数量。所以我有2张桌子。我正在尝试使用 ActiveRecord 来获取答案,它看起来像这样
class Division < ApplicationRecord
has_many :accidents
end
class Accident < ApplicationRecord
belongs_to :division
end
Division.left_joins(:accidents).where('accidents.occurred_at > ?', Time.now - 1.year).group(:name).count
在本例中 ActiveRecord 生成此 SQL
SELECT COUNT(accidents.id) AS "count_all", "divisions"."name" AS "divisions_name"
FROM "divisions"
LEFT OUTER JOIN "accidents" ON "accidents"."division_id" = "divisions"."id"
WHERE (accidents.occurred_at > '2022-07-30 20:56:10.178153')
GROUP BY "divisions"."name"
这里的问题是,如果某些除法的事故计数为0,我们将不会在查询结果中看到它,所以我需要像这样的SQL
SELECT COUNT(accidents.id) AS "count_all", "divisions"."name" AS "divisions_name"
FROM "divisions"
LEFT OUTER JOIN "accidents" ON "accidents"."division_id" = "divisions"."id" and accidents.occurred_at > '2022-07-30 20:56:10.178153'
GROUP BY "divisions"."name"
是否可以指定一些额外的加入条件? 我知道我们可以为 has_many 关系指定附加条件,但这将是静态条件。我希望它根据用户请求参数是动态的
我试图避免使用原始sql作为连接条件e.q.
Division.joins("LEFT OUTER JOIN accidents ON accidents.division_id = divisions.id
and (accidents.occurred_at > '2022-07-30 20:56:10.178153'").group(:name).count('accidents.id')
我会尝试像这样的与范围的关联
# in the model
class Division < ApplicationRecord
has_many :accidents
has_many :recent_accidents, class_name: 'Accident',
foreign_key: 'division_id',
-> { where occurred_at: (1.year.ago..) }
并且会像这样使用它:
Division.left_outer_joins(:recent_accidents)
.group(:name)
.count('accidents.id')
JOIN
来简化最终查询怎么样?
class Division < ApplicationRecord
scope :with_accidents_from, ->(occurred_at) do
joins_query =
sanitize_sql([
'LEFT OUTER JOIN accidents ON accidents.division_id = divisions.id AND accidents.occurred_at > ?',
occurred_at
])
joins(joins_query)
end
end
然后
Division.with_accidents_from(1.year.ago).group(:name).count('accidents.id')