sql >> Database >  >> RDS >> PostgreSQL

SQL waarbij de samengevoegde set alle waarden moet bevatten, maar mag meer bevatten

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.id en sports.id zijn gedefinieerd als primaire sleutel.
  • sports.name is uniek gedefinieerd.
  • (sport_id, offer_id) in offers_sports is 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


  1. Slaapstand, Postgres en arraytype

  2. Een applicatiedatabase agnostisch houden (ADO.NET versus inkapseling van DB-logica)

  3. Verbinden door eerdere equivalenten voor MySQL

  4. Controleer of de database bestaat in PostgreSQL met behulp van shell