PostgreSQL
 sql >> Database >  >> RDS >> PostgreSQL

SQL in cui il set unito deve contenere tutti i valori ma può contenerne di più

Raggruppa per offer.id , non da 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;

Assumendo l'implementazione tipica:

  • offer.id e sports.id sono definiti come chiave primaria.
  • sports.name è definito unico.
  • (sport_id, offer_id) in offers_sports è definito unico (o PK).

Non hai bisogno di DISTINCT nel conteggio. E count(*) è ancora un po' più economico.

Risposta correlata con un arsenale di possibili tecniche:

  • Come filtrare i risultati SQL in una relazione ha molti-attraverso

Aggiunto da @max (l'OP):questa è la query precedente inserita in 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