Home > Database > Mysql Tutorial > How to Query for Offers Containing a Specific Set of Sports in a Many-to-Many Relationship?

How to Query for Offers Containing a Specific Set of Sports in a Many-to-Many Relationship?

DDD
Release: 2025-01-05 07:20:44
Original
913 people have browsed it

How to Query for Offers Containing a Specific Set of Sports in a Many-to-Many Relationship?

SQL Error: "where joined set must contain all values but may contain more" for Offers and Sport Filters

In our database, we have three tables: offers, sports, and the join table offers_sports. We want to retrieve offers that include a given set of sports, with the requirement that all specified sports must be present, but additional sports may also be included.

For instance, considering the following offers:

  • Light: Yoga, Bodyboarding
  • Medium: Yoga, Bodyboarding, Surfing
  • All: Yoga, Bodyboarding, Surfing, Parasailing, Skydiving

If we query for offers containing "Bodyboarding" and "Surfing," we expect to receive both "Medium" and "All" but not "Light." However, our current query:

Offer.joins(:sports)
     .where(sports: { name: ["Bodyboarding", "Surfing"] })
     .group("sports.name")
     .having("COUNT(distinct sports.name) = 2")
Copy after login

And the SQL equivalent:

SELECT "offers".* 
FROM "offers" 
INNER JOIN "offers_sports" ON "offers_sports"."offer_id" = "offers"."id"     
INNER JOIN "sports" ON "sports"."id" = "offers_sports"."sport_id" 
  WHERE "sports"."name" IN ('Bodyboarding', 'Surfing') 
GROUP BY sports.name 
HAVING COUNT(distinct sports.name) = 2;
Copy after login

Return no results.

To rectify this, we modify our query to group by the offer ID instead of the sport name:

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;
Copy after login

or 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
Copy after login

This modification ensures that we appropriately group the results and apply the necessary filtering criteria to retrieve the desired offers that include the specified sports.

The above is the detailed content of How to Query for Offers Containing a Specific Set of Sports in a Many-to-Many Relationship?. For more information, please follow other related articles on the PHP Chinese website!

source:php.cn
Statement of this Website
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn
Popular Tutorials
More>
Latest Downloads
More>
Web Effects
Website Source Code
Website Materials
Front End Template