左连接和.includes()

问题描述 投票:0回答:2

据我了解,Rails 中执行

LEFT JOIN
的唯一方法是手动编写 SQL,如下所示:

Company.joins('LEFT JOIN people ON companies.id = people.company_id')

但是,加入其他表并使用

.includes(:people)
也变得非常棘手。

我需要使用

.includes(:people)
,否则Rails会在我访问
people
方法时生成额外的数据库请求(相关问题:当连接表时,rails在访问连接表中的字段时无论如何都会发出额外的请求

所以,这有效:

Company.joins('LEFT JOIN people ON companies.id = people.company_id')

这有效:

Company.joins('LEFT JOIN people ON companies.id = people.company_id')
      .includes(:people)

这有效:

Company.joins('LEFT JOIN people ON companies.id = people.company_id')
      .includes(:people).joins(:city)

不起作用

Company.joins('LEFT JOIN people ON companies.id = people.company_id')
      .includes(:people).joins(:city).includes(:city)

最终会加入

people
两次,当然数据库会抱怨列名不明确:
people.id

生成的SQL为:

SELECT "companies"."id" AS t0_r0, "companies"."title" AS t0_r1, 
"companies"."address" AS t0_r2, "companies"."city_id" AS t0_r3, 
"companies"."created_at" AS t0_r4, "companies"."updated_at" AS t0_r5, 
"people"."id" AS t1_r0, "people"."name" AS t1_r1, "people"."surname" AS t1_r2,
"people"."patronymic" AS t1_r3, "people"."company_id" AS t1_r4,
"people"."created_at" AS t1_r5, "people"."updated_at" AS t1_r6,
"cities"."id" AS t2_r0, "cities"."title" AS t2_r1, "cities"."created_at" AS t2_r2,
"cities"."updated_at" AS t2_r3, "cities"."test" AS t2_r4 FROM "companies" 
INNER JOIN "cities" ON "cities"."id" = "companies"."city_id"
LEFT OUTER JOIN "people" ON "people"."company_id" = "companies"."id"
LEFT JOIN people ON companies.id = people.company_id

我的理解是,当我们手动编写

JOIN
SQL 代码时,Rails 无法控制它,它无法弄清楚
people
表已经加入。

如果我这样写,它就可以工作:

Company.joins(:people).includes(:people).joins(:city).includes(:city)

但是,它使用

INNER JOIN
,但我需要
LEFT JOIN
。我仍然找不到使用
LEFT JOIN
的方法,以便这处于 Rails 的控制之下。

如何做到这一点?

ruby-on-rails left-join
2个回答
10
投票

明白了:我们需要将

.references()
.includes
结合使用;然后,Rails 执行
LEFT JOIN
,我们可以在 SQL 查询中引用连接表。

所以,这有效:

Company.includes(:people).references(:people).includes(:city).references(:city)

嗯,这看起来很混乱。


0
投票

Company.joins(:people, :city).select(*)
呢?

© www.soinside.com 2019 - 2024. All rights reserved.