PostgreSQL
 sql >> Base de données >  >> RDS >> PostgreSQL

SQL où l'ensemble joint doit contenir toutes les valeurs mais peut en contenir plus

Grouper par offer.id , pas par sports.name (ou 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;

En supposant la mise en œuvre typique :

  • offer.id et sports.id sont définis comme clé primaire.
  • sports.name est défini unique.
  • (sport_id, offer_id) dans offers_sports est défini unique (ou PK).

Vous n'avez pas besoin de DISTINCT dans le décompte. Et count(*) est encore un peu moins cher.

Réponse connexe avec un arsenal de techniques possibles :

  • Comment filtrer les résultats SQL dans une relation has-many-through

Ajouté par @max (l'OP) - il s'agit de la requête ci-dessus intégrée à 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