Groeperen op offer.id , niet door sports.name (of 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;
Uitgaande van de typische implementatie:
offer.idensports.idzijn gedefinieerd als primaire sleutel.sports.nameis uniek gedefinieerd.(sport_id, offer_id)inoffers_sportsis gedefinieerd als uniek (of PK).
Je hebt DISTINCT niet nodig bij de telling. En count(*) is zelfs een beetje goedkoper, maar toch.
Verwant antwoord met een arsenaal aan mogelijke technieken:
- SQL-resultaten filteren in een heeft-veel-door-relatie
Toegevoegd door @max (de OP) - dit is de bovenstaande query die in ActiveRecord is gerold:
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