Групиране по offer.id , а не от sports.name (или sports.id ):
SELECT o.*
FROM sports s
JOIN offers_sports os ON os.sport_id = s.id
JOIN offers o ON os.offer_id = o.id
WHERE s.name IN ('Bodyboarding', 'Surfing')
GROUP BY o.id -- !!
HAVING count(*) = 2;
Приемайки типичната реализация:
offer.idиsports.idса дефинирани като първичен ключ.sports.nameе определен уникален.(sport_id, offer_id)вoffers_sportsе дефиниран уникален (или PK).
Нямате нужда от DISTINCT в преброяването. И count(*) е дори малко по-евтино, все пак.
Свързан отговор с арсенал от възможни техники:
- Как да филтрирате SQL резултати във връзка има-много-през
Добавено от @max (ОП) - това е горната заявка, въведена в ActiveRecord:
class Offer < ActiveRecord::Base
has_and_belongs_to_many :sports
def self.includes_sports(*sport_names)
joins(:sports)
.where(sports: { name: sport_names })
.group('offers.id')
.having("count(*) = ?", sport_names.size)
end
end