尝试在Rails中连接值和group_by Postgres

时间:2014-04-18 21:44:32

标签: ruby-on-rails postgresql

我试图在视图中列出我的所有棒球运动员及其基本信息。大部分信息都位于 Players 表中。但是,我也试图拉出他们的位置,这是另一个名为位置的表格中的一列。 Players表与此Positions表没有直接关联。但是,玩家和位置都有一个has_many和belongs_to与另一个名为 GameStats 的表关联,该表包含该游戏的所有玩家统计数据,包括所扮演的位置。这是我的表格:

TABLES

Player Table

id | fname | lname
---+-------+-------
1  |  Joe  | Smith
2  |  Fred | Jones


GameStat Table

player_id | position_id
----------+-------------
    1     |     7
    1     |     7
    1     |     8
    1     |     8
    2     |     9
    2     |     9
    2     |     9
    2     |     9

Position Table

id | position
---+---------
 7 |   LF
 8 |   CF
 9 |   RF

我试图加入这三张桌子,但我没有得到我想要的。这是我的疑问:

@position_players = BatterGameStat
  .select("player_id, players.fname || ' ' || players.lname AS name, players.bats AS bats, players.throws AS throws, position_id, array_agg(positions.position) AS pos")
  .group("batter_game_stats.player_id, batter_game_stats.position_id, fname, lname, bats, throws, position")
  .joins(:player, :position)
  .order(:lname)

基本上,我会返回一个列表,但如果他们在不同游戏中扮演不同的位置,则会使用以下视图代码为每个唯一位置多次列出:

<% @position_players.each do |pp| %>
  <tr class="player">
    <td><%= link_to(pp.name, player_path(pp.player_id)) %></td>
      <td><%= pp.pos %></td>
      <td><%= pp.bats %></td>
      <td><%= pp.throws %></td>
  </tr>
<% end %>

以下是我想要归还的内容以及我得到的内容:

Desired returned html table:

   Player  |  Position(s)
-----------+-------------
Joe Smith  |  LF, CF
Fred Jones |  RF

This is what I'm actually getting:

   Player  |  Position(s) 
-----------+-------------
Joe Smith  |  LF
Joe Smith  |  CF
Fred Jones |  RF

2 个答案:

答案 0 :(得分:0)

您正在遍历位置播放器,这就是为什么您的HTML表与您的gamestats表基本相同的原因。我相信我有一个可以帮助你的解决方案。首先,您应该为has_many :throughPlayer模型添加Position关联。我还会在name模型中添加Player函数,因为您在查询中生成了它,您真的不应该这样做。

class Player < ActiveRecord::Base
  has_many :game_stats
  has_many :positions, through: :game_stats, uniq: true

  def name
    self.fname + ' ' + self.lname
  end
end

class Position < ActiveRecord::Base
  has_many :game_stats
  has_many :players, through: game_stats
end

有关关联的更多信息(我建议您阅读),请参阅Rails Guide to Associations。通过此更改,您可以极大地简化查询。

@players = Player.all

你想要的是球员,而不是联赛桌。您很少想要实际使用此特定连接模型,因为您没有任何其他列。您可以做的最后一件事是更改您的视图,如下所示:

<% @players.find_each do |p| %>
  <tr class="player">
    <td><%= link_to(p.name, player_path(pp.player_id)) %></td>
    <td><%= p.positions.join(", ") %></td>
    <td><%= p.bats %></td>
    <td><%= p.throws %></td>
  </tr>
<% end %>

这应该为您提供解决问题所需的一切。你应该仔细阅读所有Rails Guides,因为它们会帮助你极大地帮助你。当我开始时,他们肯定帮了我。

答案 1 :(得分:0)

您的问题是,您正在滥用GROUP BY position为每个人生成一组不同的position,并且与您的&#34; GROUP BY冲突以进行汇总&#34; 。在GROUP BY列表中加入position会将('Joe Smith', array['LF'])('Joe Smith', array['CF'])分成不同的行(即单独的组)。

您可以将distinct投入array_agg并将其从GROUP BY中删除。您想要的SQL如下所示:

select pl.id,
       pl.fname || ' ' || pl.lname as name,
       array_agg(distinct pos.position) 
from players pl
join game_stats gs on pl.id = gs.player_id
join positions pos on gs.position_id = pos.id
group by pl.id, pl.fname, pl.lname
order by pl.lname

演示:http://sqlfiddle.com/#!15/ac83e/3

ActiveRecord版本如下所示:

@position_players = BatterGameStat
  .select("player_id, players.fname || ' ' || players.lname AS name, array_agg(distinct positions.position) AS pos")
  .group("player_id, fname, lname")
  .joins(:player, :position)
  .order(:lname)

我建议您在视图中格式化数组时更明确一点:

<%= pp.pos.join(', ') %>