ActiveRecord通过多个连接进行选择

时间:2012-04-02 15:51:24

标签: ruby-on-rails activerecord

我正在开发基于Rails的Web服务,该服务提供有关各种运动队计划的数据。我的模型包括以下内容:

  • 每个游戏记录都有一个“主页”和一个“离开”的团队,每个团队都参考一个团队记录
  • 每个团队记录属于分部记录

我已将游戏建模如下:

class Game < ActiveRecord::Base

  # Miscellaneous validations here

  belongs_to :home_team, :class_name => Team
  belongs_to :away_team, :class_name => Team

  # Other stuff follows

end

以下是团队的模型:

class Team < ActiveRecord::Base

  # Miscellaneous validations here

  belongs_to :division

  # Other stuff follows

end

这是分部的模型:

class Division < ActiveRecord::Base

  # Miscellaneous validations here

  has_many :teams, :dependent => :destroy

  # Other stuff follows

end

我正在尝试执行一项请求,以返回主队和客队都来自特定区域的所有比赛。在伪代码中,我想要类似的东西:

SELECT games.* FROM games WHERE 
    "The division ID of the home team" = '1' AND
    "The division ID of the away team" = '1' 

我尝试过使用连接方法的各种化身,但没有一个对我有用。我最接近的是:

games = Game.joins(:home_team, :away_team).where(
    :home_team => {:division_id => params[:division_id]}, 
    :away_team => {:division_id => params[:division_id]})

但这给了我一个错误:

  SQLite3::SQLException: no such column: home_team.division_id: SELECT "games".* FROM "games" INNER JOIN "teams" ON "teams"."id" = "games"."home_team_id" INNER JOIN "teams" "away_teams_games" ON "away_teams_games"."id" = "games"."away_team_id" WHERE "home_team"."division_id" = '1' AND "away_team"."division_id" = '1'

显然,我的特定home_team和away_team的语法不起作用,因为它没有将它们映射到“team”的有效表名。但是我提出的任何其他联接变体似乎都让我更加偏离了我想要的东西。

我很感激您提供的任何帮助或对文档的参考,这些文档向我展示了如何做这类事情。

2 个答案:

答案 0 :(得分:3)

虽然@tsherif提供的答案为我提供了诀窍,但我还希望根据我在其他地方找到的信息分享我想出的另一种方法。

事实证明,当您在连接中引用同一个表两次时,ActiveRecord会为表别名实现自己的规则。该别名描述为in the Table Aliasing section of this link。根据这些信息,我能够确定我的联接中列出的第二个关联(:away_team)被别名为away_teams_games。考虑到这个表别名,我能够使用它来解决问题:

  games = Game.joins(:home_team, :away_team).where(
      :teams => {:division_id => params[:division_id]},
      :away_teams_games => {:division_id => params[:division_id]})

虽然当我第一次看到它时,这对我来说并不是完全显而易见的,但现在我看到发生的事情是有道理的。

答案 1 :(得分:1)

我想你可能会尝试这样的事情:

Game.where(["(SELECT COUNT(DISTINCT teams.id) FROM teams WHERE teams.division_id = ? AND (teams.id=games.home_team_id OR teams.id=games.away_team_id)) = 2", params[:division_id]])

你有嵌套查询,这有点烦人,但它可以让你避免在团队表上加入两次。