【问题标题】:Rails 3: Given a player, find the number of times they have been paired with each opponentRails 3:给定一个玩家,找出他们与每个对手配对的次数
【发布时间】:2020-05-22 08:20:20
【问题描述】:

我正在使用 Rails 3.2。我的架构相当复杂但很简单,我有 Pcs(代表玩家)、游戏和项目,例如:

class Game < ActiveRecord::Base
   has_many :projects

class Pc < ActiveRecord::Base
   has_many :projects

class Project < ActiveRecord::Base
   has_many :games
   belongs_to :pc

注意:GameProject 以及多对多关联都有一个表。

我正在尝试查找一个查询(ActiveRecord 优于完全原始 SQL),这样,给定一台 Pc,返回每个其他 Pc 与它们进行的游戏数。如果在同一个游戏中有两个人的项目,则一台电脑已经与另一台电脑交手。一个示例情况是:

+------+---------+----+
| Game | Project | Pc |
+------+---------+----+
|    1 |       1 |  1 |
|    1 |       2 |  1 |
|    1 |       3 |  1 |
|    1 |       4 |  2 |
|    1 |       5 |  2 |
|    2 |       6 |  1 |
|    2 |       7 |  2 |
|    3 |       8 |  1 |
|    3 |       9 |  3 |
+------+---------+----+

如果我想知道每个对手与Pc1交手的次数,结果应该是:

{2 => 2, 3 => 1}

由于 Pc2 与 Pc1 打过两场比赛,而 Pc3 只与 Pc1 打过一次。 我不在乎 Pc1 本身是否出现在结果中,我以后不会处理它。

对 Pc2 的相同查询应该返回:

{1 => 2, 3 => 0}

因为 Pc1 和 Pc1 玩过两次,而 Pc3 没有和 Pc2 玩过任何游戏。

我已经尝试了一段时间,但我似乎无法做到。

提前致谢!

编辑 1

我想我找到了一个可以完成这项工作的原始 sql 查询(仍然需要对其进行测试)。通过查看它,它看起来不像使用 ActiveRecord 查询方法可以完成。查询如下:

sql = "
SELECT 
  pc_id, 
  COUNT(DISTINCT(game_id)) 
FROM 
  (SELECT 
    g.id as game_id,  
    p.pc_id as pc_id 
  FROM games g
  INNER JOIN game_projects gp ON gp.game_id = g.id 
  INNER JOIN projects p ON p.id = gp.project_id
  WHERE g.id IN (SELECT g2.id FROM games g2 JOIN game_projects gp2 ON gp2.game_id = g2.id JOIN projects p2 ON p2.id = gp2.project_id AND p2.pc_id = #{pc.id}) 
  ) AS t 
GROUP BY pc_id;"

ActiveRecord::Base.connection.execute(sql).to_a

编辑 2

我似乎找到了解决方案,将查询和子查询一分为二:

game_ids = Game.joins(:projects).where('projects.pc_id = ?', pc.id).map(&:id)
Pc.joins(:projects => :games).where('games.id IN (?)', game_ids).group('pcs.id').count

甚至更简单,第二个是:

Project.joins(:games).where('games.id IN (?)', game_ids).group('projects.pc_id').count

编辑 3

我不在乎 Pc1 本身是否出现在结果中,我只是以后不处理它。

为避免这种情况,我们可以将AND projects.pc_id != ? 添加到WHERE 条件中。

【问题讨论】:

    标签: mysql ruby-on-rails ruby-on-rails-3


    【解决方案1】:

    我最终将查询一分为二,这使它更简单。

    game_ids = Game.joins(:projects).where('projects.pc_id = ?', pc.id).map(&:id)
    Project.joins(:games).where('games.id IN (?) AND projects.pc_id != ?', game_ids, pc.id).group('projects.pc_id').count
    

    【讨论】:

      猜你喜欢
      • 2022-11-20
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-11-20
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多