[英]Rails & Active Record: Create a scope to get the most recent child
[英]Rails ActiveRecord joining to most recent child in scope
我目前正在尝试编写一个工作人员,该工作人员必须检查最近孩子的状态并根据该状态对其进行排队。 例如,找到年龄最大的孩子在学校的父母
class Parent
has_many :children
end
class Child
belongs_to :parent
lookup_for :status, symbolize: true
end
目前我的范围是:
Parent.joins(:children).
where("children.birth_date =
(SELECT MAX(children.birth_date)
FROM children
WHERE children.parent_id = parents.parent_id").
where('children.status = ?', Status[:in_school]').pluck(:parent_id)
似乎应该有一个更好的方法来执行此操作。 有任何想法吗
为了澄清起见,我正在寻找所有最大的孩子还在上学的父母
如果您在查询中经常使用第一个/或最后一个孩子,我会将其添加为父项中的字段
class Parent
belongs_to :youngest_child, class_name: Child, inverse_of: :parent
end
好的,您可以将某些逻辑推入joins()语句中,如下所示,但我看不出如何才能摆脱必须在某个地方进行子查询的麻烦。
Parent.joins(%Q{left join children on children.parent_id = parents.id
and children.birth_date = (select max(birth_date) from children
where children.parent_id = parents.id)}).
where('children.status = ?', Status[:in_school]')
看起来像那样。 高温超导
或者,您可以使用order and last查找最后一个孩子,然后检查该孩子在内存中的状态。 这种方法最多只能带一个孩子,因此表现合理。 如下所示:
child=Child.order(:birth_date).joins(:parent).last
parent.do_stuff if child.in_school?
您的查询有效-完成工作,并且清楚您要做什么。 我在我现在正在处理的应用程序中的相似关联上测试了您的模式, ActiveRecord
将所有模式正确地组合到一个查询中,并且花费了1.4ms 。
如果要优化性能,可以使用联接来获取最老的孩子,而不是子查询:
Parent.joins("INNER JOIN (
SELECT c1.*
FROM children c1
LEFT JOIN children c2 ON (c1.parent_id = c2.parent_id AND c1.birthdate > c2.birthdate)
WHERE c2.parent_id IS NULL
) c ON parent.parent_id = c.parent_id")
.where('children.status = ?', Status[:in_school])
.pluck(:parent_id)
由于它使用了一种手动外部联接,因此它的用途不太清楚,但是它也允许嵌套联接也使用索引。 在与上述相同的测试方案中,此操作在0.9毫秒内执行了相同的查询(几乎快了两倍)。 那是在一个很小的数据库中,只有几百条记录。 拥有数百万条记录,差异将非常明显。
感谢这个StackOverflow的答案 ,为联接模式。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.