使用连接表选择属于另外两个的行

时间:2014-03-07 23:15:42

标签: sql ruby-on-rails postgresql activerecord relational-division

鉴于两个模型PlayerTeam如何选择两个玩家特定玩家所属的所有球队?

示例Rails模型和db表设置:

Rails模型:

class Player < ActiveRecord::Base
  has_and_belongs_to_many :teams, uniq: true
end
class Team < ActiveRecord::Base
  has_and_belongs_to_many :players, uniq: true
end

SQL表

    teams         players            players_teams
+----------------------------------------------------+
| id | name |   | id | name |  | player_id | team_id |
+----+------+   +----+------+  +-----------+---------+
|  1 | Foo  |   |  1 | Jack |  |      1    |    1    |
|  2 | Bar  |   |  2 | Jill |  |      1    |    2    |
|    |      |   |    |      |  |      2    |    1    |

如何选择所有同时拥有Jack和Jill的球队? (在这种情况下,只是Foo团队。)

4 个答案:

答案 0 :(得分:2)

这是一个非常棘手的问题!它不仅仅是where子句中的OR / AND。 在这里,您可以使用GROUP BY和MAX

在单个SQL查询中找到解决方案
SELECT t.*
  FROM teams t 
  JOIN players_teams pt ON t.id = pt.team_id
  JOIN players p ON p.id = pt.player_id
WHERE p.name IN ('Jack', 'Jill')
GROUP BY t.id
HAVING MAX(p.name = 'Jack') = 1 AND MAX(p.name = 'Jill') = 1

SQL Fiddle

在ActiveRecord中应该是这样的(未经测试的)

Team.joins(:players).where("players.name IN (?)", ["Jack", "Jill"])
.group("teams.id")
.having("MAX(players.name = ?) = 1 AND MAX(players.name = ?) = 1", "Jack", "Jill")

答案 1 :(得分:1)

您可以获得两个单独查询的交集,例如

Team.includes(:players).where(players: { name: 'Jack' }) & Team.includes(:players).where(players: { name: 'Jill' })

对于单个查询,请尝试以下

Team.includes(:players).where(players: { name: ['Jack', 'Jill'] }).group('teams.id').having('COUNT(players.id) = 2')

答案 2 :(得分:0)

Teams.all(:include => :player, conditions => ["player.name in (?)", ["Jack","Jill"]])

答案 3 :(得分:0)

这是我提出的使用子查询的解决方案。有没有人有更清洁的AREL方式来实现这个目标?

SELECT te1.* FROM (
  SELECT DISTINCT "teams".* FROM "teams"
  INNER JOIN "players_teams" ON "teams"."id" = "players_teams"."team_id"
  WHERE "players_teams"."player_id" = 2
) te1 INNER JOIN "players_teams" ON "te1"."id" = "players_teams"."team_id"
  WHERE "players_teams"."player_id" = 1;