【问题标题】:ActiveRecord select through multiple joinsActiveRecord 通过多个连接选择
【发布时间】:2012-04-02 15:51:24
【问题描述】:

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

  • 每条比赛记录都有一个“主场”和一​​个“客场”球队,每个球队都引用了一个球队记录
  • 每个 Team 记录都属于一个 Division 记录

我已经将游戏建模如下:

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

这是Division的模型:

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' 

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

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 的语法不起作用,因为它没有将它们映射到“teams”的有效表名。但我想出的任何其他连接变体似乎让我离我想要的更远。

如果您能提供任何帮助或参考向我展示如何执行此类操作的文档,我将不胜感激。

【问题讨论】:

    标签: ruby-on-rails activerecord


    【解决方案1】:

    虽然@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]})
    

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

    【讨论】:

    • 如果您不想依赖提前了解别名方案,也可以使用 arel
    • @FrederickCheung 你能详细说明一下吗?
    【解决方案2】:

    我认为您可以尝试以下方法:

    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]])
    

    你有嵌套查询,这有点烦人,但它可以让你避免两次加入到 teams 表中。

    【讨论】:

    • 谢谢@tsherif - 这对我有用。它没有我希望的那么优雅,但它确实回答了我提出的问题,所以我会将此标记为已接受的答案。 (虽然我确实在其他地方找到了另一个答案,所以我会发布以防其他人好奇)
    猜你喜欢
    • 2017-01-27
    • 1970-01-01
    • 2012-07-03
    • 1970-01-01
    • 1970-01-01
    • 2017-10-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多