PostgreSQL
 sql >> Base de Dados >  >> RDS >> PostgreSQL

SQL onde o conjunto unido deve conter todos os valores, mas pode conter mais


Agrupar por offer.id , não por 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;

Assumindo a implementação típica:
  • offer.id e sports.id são definidos como chave primária.
  • sports.name é definido como único.
  • (sport_id, offer_id) em offers_sports é definido como único (ou PK).

Você não precisa de DISTINCT na contagem. E count(*) é ainda um pouco mais barato, ainda.

Resposta relacionada com um arsenal de técnicas possíveis:
  • Como filtrar resultados de SQL em uma relação de muitos

Adicionado por @max (o OP) - esta é a consulta acima inserida no 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