Agrupar por offer.id , no por sports.name (o 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;
Asumiendo la implementación típica:
offer.idysports.idse definen como clave principal.sports.namese define único.(sport_id, offer_id)enoffers_sportsse define único (o PK).
No necesitas DISTINCT en el conteo Y count(*) es incluso un poco más barato, todavía.
Respuesta relacionada con un arsenal de posibles técnicas:
- Cómo filtrar los resultados de SQL en una relación de varios procesos
Agregado por @max (el OP):esta es la consulta anterior incluida en 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