我正在开发一个允许会员进行调查的应用程序(会员与Response有一对多的关系).Response保存member_id,question_id及其答案.
调查全部或全部提交,因此如果该成员的响应表中有任何记录,则他们已完成调查.
我的问题是,如何重新编写下面的查询,以便它实际工作?在SQL中,这将是EXISTS关键字的主要候选者.
def surveys_completed
members.where(responses: !nil ).count
end
Run Code Online (Sandbox Code Playgroud)
MrY*_*iji 101
您可以使用includes
然后测试相关的响应是否存在,如下所示:
def surveys_completed
members.includes(:responses).where('responses.id IS NOT NULL')
end
Run Code Online (Sandbox Code Playgroud)
这是一个替代方案,包括joins
:
def surveys_completed
members.joins(:responses)
end
Run Code Online (Sandbox Code Playgroud)
使用Rails 4的解决方案:
def surveys_completed
members.includes(:responses).where.not(responses: { id: nil })
end
Run Code Online (Sandbox Code Playgroud)
类似的问题:
您可以使用Where Exists gem EXISTS
以优雅的Rails-ish方式使用SQL 关键字:
members.where_exists(:responses).count
Run Code Online (Sandbox Code Playgroud)
当然你也可以使用原始SQL:
members.where("EXISTS" \
"(SELECT 1 FROM responses WHERE responses.member_id = members.id)").
count
Run Code Online (Sandbox Code Playgroud)
Rails 6.1 引入了一种检查关联是否缺失的新方法 - where.missing。
请看一下下面的代码片段:
# Before:
Post.left_joins(:author).where(authors: { id: nil })
# After:
Post.where.missing(:author)
Run Code Online (Sandbox Code Playgroud)
这是在后台使用的 SQL 查询的示例:
Post.where.missing(:author)
# SELECT "posts".* FROM "posts"
# LEFT OUTER JOIN "authors" ON "authors"."id" = "posts"."author_id"
# WHERE "authors"."id" IS NULL
Run Code Online (Sandbox Code Playgroud)
因此,您的具体情况可以重写如下:
def surveys_completed
members.where.missing(:response).count
end
Run Code Online (Sandbox Code Playgroud)
谢谢。
资料来源:
笔记:
您还可以使用子查询:
members.where(id: Response.select(:member_id))
Run Code Online (Sandbox Code Playgroud)
与includes
它相比,它不会加载关联的模型(如果您不需要它们,这是一个性能优势)。
小智 6
如果您使用的是 Rails 5 及更高版本,则应使用left_joins
. 否则,手动“LEFT OUTER JOINS”也将起作用。这比/sf/answers/1276449891/ 中includes
提到的使用性能更高。将尝试将相关对象加载到内存中,而将构建“LEFT OUTER JOINS”查询。includes
left_joins
def surveys_completed
members.left_joins(:responses).where.not(responses: { id: nil })
end
Run Code Online (Sandbox Code Playgroud)
即使没有相关记录(如上面的查询,您通过 nil 查找)includes
仍然使用更多内存。在我的测试中,我发现包括在 Rails 5.2.1 上使用了大约 33 倍的内存。在 Rails 4.2.x 上,与手动连接相比,内存增加了大约 44 倍。
请参阅此测试要点:https : //gist.github.com/johnathanludwig/96fc33fc135ee558e0f09fb23a8cf3f1
归档时间: |
|
查看次数: |
30373 次 |
最近记录: |