Mysql Rails 5使用includes()和where()左外连接
我在使用includes()和where()获取预期行为方面花了很长时间 我想要的结果:Mysql Rails 5使用includes()和where()左外连接,mysql,ruby-on-rails,activerecord,left-join,ruby-on-rails-5,Mysql,Ruby On Rails,Activerecord,Left Join,Ruby On Rails 5,我在使用includes()和where()获取预期行为方面花了很长时间 我想要的结果: -所有学生(即使他们没有登记入住) -所有在图书馆登记的人 我得到的结果是: -只有在图书馆登记的学生 -所有在图书馆登记的学生 目前我的代码基于以下内容: 它描述了我想要的行为: SELECT first_name, C.id FROM students S LEFT OUTER JOIN check_ins C ON C.student_id = S.id AND location IN ('Libr
-所有学生(即使他们没有登记入住)
-所有在图书馆登记的人 我得到的结果是:
-只有在图书馆登记的学生
-所有在图书馆登记的学生
目前我的代码基于以下内容: 它描述了我想要的行为:
SELECT first_name, C.id FROM students S LEFT OUTER JOIN check_ins C ON C.student_id = S.id AND location IN ('Library');
如果在这个包含查询的情况下,没有任何注释
物品,所有物品仍将被加载
我的代码:
此SQL查询提供了我想要的连接行为:
SELECT first_name, C.id FROM students S LEFT OUTER JOIN check_ins C ON C.student_id = S.id AND location IN ('Library');
我认为这是创建所需查询的唯一方法
Student.joins("LEFT OUTER JOIN check_ins ON check_ins.student_id = students.id AND check_ins.location = 'Library'")
参考资料:就纯SQL而言,您想要的是:
LEFT OUTER JOIN "check_ins" ON "check_ins"."student_id" = "students"."id"
AND location IN ('Library')
但是(afaik)无法让ActiveRecord将关联标记为已加载
老实说,我从来不喜欢只预加载关联的一个子集
因为应用程序的某些部分可能假定它是
满载的。只有当您将数据传送到
显示它。-罗伯特·潘科维茨基 <> P>所以在这种情况下,你应该考虑预加载所有的数据,并使用类似A的东西来选择<代码> CyjysIs<代码> > < /P>
我还建议您为位置创建一个单独的表。尝试了一种使用具有关系的作用域的新方法,期望预加载所有内容并将其过滤掉,但令人惊喜的是,作用域实际上为我提供了我想要的准确行为(直接到急切加载) 结果如下: 此ActiveRecord调用会拉入完整的学生列表,并加载签入:
@students = Student.all.includes(:check_ins)
签入的范围可以限制在has\u many声明中:
Class Student < ApplicationRecord
has_many :check_ins, -> {where('location = 'Library'}, dependent: :destroy
end
宾果 p、 您可以在此处阅读有关将作用域与关联一起使用的更多信息:
子查询将类似于学生的
(选择count('check\u-ins.location'),其中的'check\u-ins.location')。check\u-IN\u-count
。我已经好几年没有接触过MySQL了,也没有安装它来试用。你就是那个人,一个多小时后,我发现你的加入代码解决了我的一个大问题!我的目标是急切地加载关联以最小化查询的数量。虽然这种方法可以获得正确的数据,但它使用了大量的查询来获得这些数据。{where('location='Library'}
=>{where('location='Library')}
或{where(location:'Library')}
Student.joins("LEFT OUTER JOIN check_ins ON check_ins.student_id = students.id AND check_ins.location = 'Library'")
LEFT OUTER JOIN "check_ins" ON "check_ins"."student_id" = "students"."id"
AND location IN ('Library')
class Student < ApplicationRecord
has_many :check_ins
def self.joins_check_ins
joins( <<~SQL
LEFT OUTER JOIN "check_ins" ON "check_ins"."student_id" = "students"."id"
AND location IN ('Library')
SQL
)
end
end
irb(main):041:0> Student.joins_check_ins.map {|s| s.check_ins.loaded? }
Student Load (1.0ms) SELECT "students".* FROM "students" LEFT OUTER JOIN "check_ins" ON "check_ins"."student_id" = "students"."id"
AND location IN ('Library')
=> [false, false, false]
irb(main):042:0> Student.joins_check_ins.map {|s| s.check_ins.size }
Student Load (2.3ms) SELECT "students".* FROM "students" LEFT OUTER JOIN "check_ins" ON "check_ins"."student_id" = "students"."id"
AND location IN ('Library')
(1.2ms) SELECT COUNT(*) FROM "check_ins" WHERE "check_ins"."student_id" = $1 [["student_id", 1]]
(0.7ms) SELECT COUNT(*) FROM "check_ins" WHERE "check_ins"."student_id" = $1 [["student_id", 2]]
(0.6ms) SELECT COUNT(*) FROM "check_ins" WHERE "check_ins"."student_id" = $1 [["student_id", 3]]
@students = Student.all.includes(:check_ins)
Class Student < ApplicationRecord
has_many :check_ins, -> {where('location = 'Library'}, dependent: :destroy
end
Student Load (0.7ms) SELECT "students".* FROM "students"
CheckIn Load (1.2ms) SELECT "check_ins".* FROM "check_ins" WHERE location = 'Library') AND "check_ins"."student_id" IN (6, 7, 5, 3, 1, 8, 9, 4, 2)