如果关系存在,我们已经离开了一个表,以便我们可以按列排序:
people = Person
.joins("LEFT JOIN addresses ON addresses.id = people.address_id")
.order("addresses.country")
.all
这导致单个SQL查询,但我希望people.first.address
不会触发SQL来加载地址。我是离开加入的,因为有些人没有地址。
.includes(:address)
会触发单独的查询。
您可以使用includes
执行我使用内部联接建议的内容,但会触发2个SQL查询:
Person.includes(:address).all
虽然joins
+ includes
只触发一个(但是INNER联接):
Person.joins(:address).includes(:address).all
如果在急切加载时强制加入,则活动记录也会使用左联接
.eager_load(:addresses)
。
您是否可以使用现有的左连接并使用这些结果加载轨道?到目前为止,我无法找到它。
答案 0 :(得分:3)
试试这个:
people = Person.
eager_load(:address).
merge(Address.order("coalesce(country, '')")).
all
people.first.address
eager_load
通过执行LEFT OUTER JOIN强制加载。
我在国家/地区添加了合并,因此您可以更好地控制没有地址的人在结果中出现的位置。
以下是我的看法:
people = Person.
eager_load(:address).
merge(Address.order("coalesce(country, '')")).
all
(0.5ms) SELECT DISTINCT COUNT(DISTINCT "people"."id") FROM "people" LEFT OUTER JOIN "addresses" ON "addresses"."person_id" = "people"."id"
SQL (2.1ms) SELECT "people"."id" AS t0_r0, "people"."name" AS t0_r1, "people"."created_at" AS t0_r2, "people"."updated_at" AS t0_r3, "addresses"."id" AS t1_r0, "addresses"."person_id" AS t1_r1, "addresses"."address" AS t1_r2, "addresses"."country" AS t1_r3, "addresses"."created_at" AS t1_r4, "addresses"."updated_at" AS t1_r5 FROM "people" LEFT OUTER JOIN "addresses" ON "addresses"."person_id" = "people"."id" ORDER BY coalesce(addresses.country, '')
people.first.address
nil
people.last.address
#<Address:0x007febabb508a8> {
:id => 1,
:person_id => 4,
:address => "24175 Gerhold Prairie",
:country => "O",
:created_at => Thu, 01 Feb 2018 18:47:45 UTC +00:00,
:updated_at => Thu, 01 Feb 2018 18:47:45 UTC +00:00
}
请注意,访问地址时不会运行任何查询
我指出你已经通过一个离开外部的表来命令,所以你需要决定如何处理空值。
答案 1 :(得分:2)
Well, in your case you could select your query creating an alias for the fields you are going to use from address something like this:
people = Person
.joins("LEFT JOIN addresses ON addresses.id = people.address_id")
.select("people.*, addresses.country as address_country")
.order("address_country")
.all
This won't change your desired query and will not result in extra queries, not for country at least.
答案 2 :(得分:1)
您可以#references
与#includes
LEFT JOIN
使用people = Person
.includes(:addresses)
.references(:addresses)
.order("addresses.country")
您的关系,并实现您的目标。
#references
这将产生一个查询和所有人,无论他们是否有地址,并且还急于加载地址以避免可怕的N + 1查询。
文档在解释LEFT JOIN
将添加WHERE
方面做得不是很好,但其目的是允许添加SQL子句(ORDER
,结合GROUP
的关系#includes
,ViewController
等)。