【问题标题】:Rails eager_load with conditions on association带有关联条件的 Rails eager_load
【发布时间】:2016-10-30 13:48:38
【问题描述】:

我有一个 Rails 应用程序,它有 Stations(气象站)和 Observations。该应用程序在地图上显示了许多具有当前风速和风向的气象站。

我有一个用于stations#index 方法的方法,它选择站点并加入每个站点的最新观察。

class Station < ActiveRecord::Base
  has_many :observations
  def self.with_observations(limit = 1)
    eager_load(:observations).where(
      observations: { id: Observation.pluck_from_each_station(limit) }
    )
  end
end

Observation.pluck_from_each_station 返回一个 id 数组。 observations 表包含数千行,因此这是防止 Rails 急切加载数千条记录所必需的。

这个方法应该返回所有的——不管有没有观察。但目前情况并非如此。

it "includes stations that have no observations" do
  new_station = create(:station)
  stations = Station.with_observations(2)
  expect(stations).to include new_station # fails
end

据我了解,LEFT OUTER JOIN 应该返回所有行,无论连接表中是否有任何结果。为什么这没有按预期工作?

这是生成的 SQL 示例:

SELECT "stations"."id" AS t0_r0,
       "stations"."name" AS t0_r1,
       "stations"."hw_id" AS t0_r2,
       "stations"."latitude" AS t0_r3,
       "stations"."longitude" AS t0_r4,
       "stations"."balance" AS t0_r5,
       "stations"."timezone" AS t0_r6,
       "stations"."user_id" AS t0_r7,
       "stations"."created_at" AS t0_r8,
       "stations"."updated_at" AS t0_r9,
       "stations"."slug" AS t0_r10,
       "stations"."speed_calibration" AS t0_r11,
       "stations"."firmware_version" AS t0_r12,
       "stations"."gsm_software" AS t0_r13,
       "stations"."description" AS t0_r14,
       "stations"."sampling_rate" AS t0_r15,
       "stations"."status" AS t0_r16,
       "observations"."id" AS t1_r0,
       "observations"."station_id" AS t1_r1,
       "observations"."speed" AS t1_r2,
       "observations"."direction" AS t1_r3,
       "observations"."max_wind_speed" AS t1_r4,
       "observations"."min_wind_speed" AS t1_r5,
       "observations"."temperature" AS t1_r6,
       "observations"."created_at" AS t1_r7,
       "observations"."updated_at" AS t1_r8,
       "observations"."speed_calibration" AS t1_r9
FROM   "stations"
       LEFT OUTER JOIN
       "observations"
       ON "observations"."station_id" = "stations"."id"
WHERE  "observations"."id" IN (450, 500, 550, 600, 650, 700, 750, 800);

【问题讨论】:

  • "observations"."id" IN (..) 应该在ON 子句内,而不是WHERE 子句内。

标签: sql ruby-on-rails postgresql ruby-on-rails-4 activerecord


【解决方案1】:

我认为会发生这种情况,因为您排除了"observations"."id"left join 之后为空的记录:

eager_load(:observations).where(
  '"observations"."id" is null or "observations"."id" in (?)', Observation.pluck_from_each_station(limit)
)

逻辑上在两个条件下与 left join 相同,但由于 rails 没有此功能,您可以使用 where 子句解决它。

【讨论】:

  • 发生这种情况是因为左连接的右表上的条件应该放在ON 子句中。当它们在 WHERE 子句上时,连接将转换为内部连接。
  • @sagi:是的,但也可以在where 子句中完成。
  • 规范正在通过。将查看是否有可能让 AR 生成 @sagi 建议的 on 子句并仍然加载关联。
  • @sagi:使用joins 和棘手的预加载,要么是那个,要么是难以消化的 ar 查询。
  • 哦,我明白了。认为这更容易,因为它是 LEFT JOIN 的基本内容。
猜你喜欢
  • 1970-01-01
  • 2018-01-24
  • 2011-03-26
  • 2016-04-15
  • 1970-01-01
  • 2021-11-17
  • 2023-03-20
  • 1970-01-01
  • 2013-12-26
相关资源
最近更新 更多