提问人:David Asatryan 提问时间:7/31/2023 最后编辑:mechnicovDavid Asatryan 更新时间:9/13/2023 访问量:58
如何对 ActiveRecord 联接应用其他条件
How apply additional conditions for ActiveRecord joins
问:
假设我尝试计算一段时间内每个部门的事故计数。所以我有 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')
答:
1赞
spickermann
7/31/2023
#1
我会尝试与这样的范围相关联
# 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')
评论
0赞
David Asatryan
7/31/2023
谢谢,但是如果我想要occurred_at的动态参数,具体取决于用户参数怎么办?
0赞
spickermann
7/31/2023
然后,您将需要将 与较长的字符串一起使用。outer_left_joins
1赞
mechnicov
7/31/2023
#2
使用范围来简化最终查询是怎么回事?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')
评论
0赞
David Asatryan
7/31/2023
哇,有趣,看起来我想要的,谢谢,会尝试这种方法
评论
where
joins
LEFT JOIN
occurred_at
accidents
null