sql >> Base de Datos >  >> RDS >> PostgreSQL

SQL donde el conjunto unido debe contener todos los valores pero puede contener más

Agrupar por offer.id , no por 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;

Asumiendo la implementación típica:

  • offer.id y sports.id se definen como clave principal.
  • sports.name se define único.
  • (sport_id, offer_id) en offers_sports se define único (o PK).

No necesitas DISTINCT en el conteo Y count(*) es incluso un poco más barato, todavía.

Respuesta relacionada con un arsenal de posibles técnicas:

  • Cómo filtrar los resultados de SQL en una relación de varios procesos

Agregado por @max (el OP):esta es la consulta anterior incluida en 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