ruby-on-rails 左连接和.includes()

bwitn5fc  于 2023-10-21  发布在  Ruby
关注(0)|答案(2)|浏览(185)

据我所知,在Rails中执行LEFT JOIN的唯一方法是手动编写SQL,如下所示:

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

但是,连接其他表并使用.includes(:people)也变得非常棘手。
我需要使用.includes(:people),因为否则每当我访问people方法时,Rails都会生成额外的db请求(相关问题:When joining table, rails anyway makes additional request when accessing fields from joined table
这样就行了

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两次,当然db会抱怨列名不明确: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的控制下。
如何做到这一点?

0sgqnhkj

0sgqnhkj1#

明白了:我们需要将.references().includes结合使用;然后,Rails执行LEFT JOIN,我们可以在SQL查询中引用连接表。
这样就行了

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

嗯,这里看起来很乱。

bejyjqdl

bejyjqdl2#

推荐Company.joins(:people, :city).select("*")假设公司与人和城市都有直接关联。
这在间接关系中也是可能的。例如,公司“有很多”人和城市。然后,城市“有许多”视图。Company.joins(:people, city: :views).select("*")
如果有两个要进行内部联接的嵌套关系。让我们再加上一个与城市的关系。城市“有许多”景观和鲸鱼。
Company.joins(:people, city: [:views, :whales]).select("*")

相关问题