PostgreSQL
 sql >> Datenbank >  >> RDS >> PostgreSQL

SQL, bei dem verbundene Mengen alle Werte enthalten müssen, aber möglicherweise mehr enthalten

Gruppieren Sie nach offer.id , nicht nach sports.name (oder 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;

Angenommen die typische Implementierung:

  • offer.id und sports.id sind als Primärschlüssel definiert.
  • sports.name ist eindeutig definiert.
  • (sport_id, offer_id) in offers_sports ist eindeutig definiert (oder PK).

Sie brauchen DISTINCT nicht in der Zählung. Und count(*) ist sogar noch etwas billiger.

Verwandte Antwort mit einem Arsenal möglicher Techniken:

  • So filtern Sie SQL-Ergebnisse in einer Has-Viele-Durch-Beziehung

Hinzugefügt von @max (dem OP) – dies ist die obige Abfrage, die in ActiveRecord gerollt wird:

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