反向查询has_many :through



场景:

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(,我想知道是否有任何团队由这两个球员组成。假设我有一个由用户 1、2 和 5 组成的团队。查询不应带来此团队。

我如何使用对我有利的ActiveRecord语义来做到这一点?从一支球队中得到所有球员很容易,但我找不到相反的方法。

更新:啊!我在纯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)

您可以使用两个 where 子句:

一个用于获取正好有两个用户的所有Teams

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

其次是与用户的所有Teams15

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"))
Team.join(:users).where('users.id in (?)', [1,5]).
select { |team| team.users.map(&:id).sort == [1,5] }

以前的答案(对于预先编辑的问题(

这对你有用吗?

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

更好?

SQL 仅选择存在精确多个关系的行

最新更新