我目前正在尝试编写一名工作人员,该工作人员必须检查最近孩子的状态并根据该状态对其进行排队。例如,找到年龄最大的孩子在校的父母
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)
似乎应该有更好的方法来做到这一点。任何想法
澄清我正在寻找所有仍在上学的父母
答案 0 :(得分:0)
如果您在查询中经常使用第一个/或最后一个孩子,我会将它们添加为父项中的字段
class Parent
belongs_to :youngest_child, class_name: Child, inverse_of: :parent
end
答案 1 :(得分:0)
好吧,您可以将一些逻辑推送到如下所示的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]')
那就像那样。 HTH
答案 2 :(得分:0)
或者,您可以使用order和last查找最后一个子项,然后检查子项内存中的状态。这种方法最多只会有一个孩子,所以表现合理。如下所示:
child=Child.order(:birth_date).joins(:parent).last
parent.do_stuff if child.in_school?
答案 3 :(得分:0)
您的查询有效 - 它完成了工作,很明显您的目标是什么。我在我正在处理的应用中测试了您的模式,并且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.9ms 中执行相同的查询(几乎快两倍)。那是一个非常小的数据库,只有几百条记录。凭借数百万条记录,差异将是显而易见的。
感谢这个StackOverflow answer,对于连接模式。