Rails 3 / SQL - комплекс "существует?" запрос - PullRequest
3 голосов
/ 11 сентября 2011

Мои модели

class Team < ActiveRecord::Base
  has_many :team_players
  has_many :players, :through => :team_players
end

class TeamPlayer < ActiveRecord::Base
  belongs_to :team
  belongs_to :player
end
  • Команды могут иметь разное количество игроков
  • Игроки могут быть во многих командах
  • Получение team_id, если он уже существует <- Моя проблема </strong>

При создании новой команды я в основном выбираю несколько игроков во вложенной форме. После создания мне нужно проверить, существует ли команда с составом игрока точный .

Пример:

  • Команда 1: A (идентификатор 1) и B (идентификатор 2)
  • Команда 2: A (идентификатор 1), B (идентификатор 2) и C (идентификатор 3)

Допустим, я создаю новую команду с A и B , тогда мне нужен запрос, чтобы как-то сказать мне, существует ли он или нет, возвращая team_id или что-то, или пустой результат.

Я играл с подобными запросами, но без удовлетворительного результата

SELECT *, count(id) as c FROM "team_players" WHERE player_id IN (1,3) GROUP BY team_id HAVING c = 2

1 Ответ

1 голос
/ 11 сентября 2011

Я думаю, вы можете сделать это в два этапа:

  1. Найдите команды, в которых есть все игроки, на которых вы смотрите.
  2. Проверьте, есть ли в этих командах больше игроков, чем указано в наборе игроков.

Это означает:

select team_id
from team_players
where team_id in (
    select team_id
    from team_players
    where player_id in (1,3)
    group by team_id
    having count(player_id) = 2
)
group by team_id
having count(player_id) = 2

Учитывая это в team_players:

team_id|player_id
     1 | 1
     1 | 3
     1 | 4
     2 | 1
     2 | 3
     3 | 3

Приведенный выше запрос говорит team_id = 2, и это ваше точное совпадение. Используемый вами запрос дает вам команды, которые содержат рассматриваемых игроков в качестве подмножества, а не команды, которые по настройке равны рассматриваемым игрокам.

Если вы хотите узнать только, существует ли такая команда, поместите этот запрос в вызов select_rows и все готово:

class Team < ActiveRecord::Base
    # players is an array of Fixnum player IDs
    def self.team_exist?(players)
        return false if(!players.present?)
        connection.select_rows(%Q{
            select team_id
            from team_players
            where team_id in (
                select team_id
                from team_players
                where player_id in (#{players.join(',')})
                group by team_id
                having count(player_id) = #{players.length}
            )
            group by team_id
            having count(player_id) = #{players.length}
        }).present?
    end
end

Интерполяция #{players.join(',')} предполагает, что team_exist? получает массив Fixnum, поэтому вы захотите правильно очистить ваши данные в вызывающей программе или добавить players = players.map(&:to_i) перед вызовом connect.select_rows, чтобы очистить его внутри team_exist?.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...