反向查询has_many:through

时间:2017-08-16 01:03:59

标签: sql ruby-on-rails rails-activerecord

场景:

Team
has_many :players, dependent: :destroy
has_many :users, through: :players

Player
belongs_to :team
belongs_to :user

User

所以,让我们说我有4个不同用户的团队:

Team 1
User 1, User 2

Team 2
User 2, User 3

Team 3
User 1

Team 4
User 2, User 4, User 5

现在,假设我有两个用户的ID,(User 1User 5),我想知道是否有任何团队包含 ONLY 这些两名球员。假设我有一个由用户1,2和5组成的团队。该查询不应该带来这个团队。

我如何使用ActiveRecord语义对我有利?从团队中获取所有玩家很容易,但我无法找到相反的方法。

3 个答案:

答案 0 :(得分:1)

您可以使用两个where子句:

一个让所有Teams只有两个用户。

Team.joins(:users).group("teams.id").having("count('distinct users.id') = 2").select("teams.id")

让所有Teams与用户15保持一致。

Team.joins(:users).where('users.id in (?)', [1,5]).group("teams.id").having("count('distinct users.id') = 2").select("teams.id")

这两者的交叉应该可以满足您的需求。 所以要把它全部结合起来:

Team.where(id: Team.joins(:users).group("teams.id").having("count('distinct users.id') = 2").select("teams.id")).where(id: Team.joins(:users).where('users.id in (?)', [1,5]).group("teams.id").having("count('distinct users.id') = 2").select("teams.id"))

答案 1 :(得分:1)

更新: AH!我在纯SQL中得到它:

users = User.first(2)
Team.joins(:users).group('teams.id').having('SUM( CASE WHEN users.id in (?) THEN 1 ELSE -1 END ) = ?', users, users.count)

尝试一下,让我知道它是否适合你(在这里工作:http://sqlfiddle.com/#!17/bb2a9/8和相同的例子,但有3个玩家:http://sqlfiddle.com/#!17/bb2a9/10

这在数据库级别上没有优化,因为它使用了大量的ruby / rails代码,但你可以试试吗?

users = User.first(2)
# find teams with that exact number of players associated
teams = Team.joins(:users).group('teams.id').having('COUNT(users.id) = ?', users.count)
# find players referencing to those teams with other users than the ones specified
players_to_ignore = Player.where(team_id: teams).where('user_id NOT IN (?)', users)
# get Teams where associated players id is not in the previous list
Team.where(id: teams).joins(:players).where('players.id NOT IN (?)', players_to_ignore)

答案 2 :(得分:0)

Team.join(:users).where('users.id in (?)', [1,5])

上一个答案(预编辑问题)

这会对你有用吗?

# user.rb
has_many :teams, through: :works
has_many :works, foreign_key: :user_id

您可以通过

在用户模型上执行相同的操作
Team.join(:users).where('users.id in (?)', [1,5]).
select { |team| team.users.map(&:id).sort == [1,5] }

回应您的修改&评论

哈克:

              skeptical    skeptically ... ... ...      color
stories[2]        0             0      ... ... ...   TFI-DF value

更好?

  

SQL Select only rows where exact multiple relationships exist