Maison > base de données > tutoriel mysql > Comment rechercher des offres contenant un ensemble spécifique de sports dans une relation plusieurs-à-plusieurs ?

Comment rechercher des offres contenant un ensemble spécifique de sports dans une relation plusieurs-à-plusieurs ?

DDD
Libérer: 2025-01-05 07:20:44
original
913 Les gens l'ont consulté

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

Erreur SQL : "où l'ensemble joint doit contenir toutes les valeurs mais peut en contenir plus" pour les offres et les filtres sportifs

Dans notre base de données, nous avons trois tables : offres, sports, et la table de jointure deals_sports. Nous souhaitons récupérer les offres qui incluent un ensemble de sports donné, avec l'exigence que tous les sports spécifiés doivent être présents, mais des sports supplémentaires peuvent également être inclus.

Par exemple, en considérant les offres suivantes :

  • Léger : Yoga, Bodyboard
  • Moyen : Yoga, Bodyboard, Surf
  • Tous : Yoga, Bodyboard, Surf, parachute ascensionnel, parachutisme

Si nous recherchons des offres contenant « Bodyboard » et « Surf », nous nous attendons à recevoir à la fois « Moyen » et « Tous », mais pas « Léger ». Cependant, notre requête actuelle :

Offer.joins(:sports)
     .where(sports: { name: ["Bodyboarding", "Surfing"] })
     .group("sports.name")
     .having("COUNT(distinct sports.name) = 2")
Copier après la connexion

Et l'équivalent SQL :

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;
Copier après la connexion

Ne renvoie aucun résultat.

Pour rectifier cela, nous modifions notre requête pour regrouper par l'identifiant de l'offre au lieu du nom du sport :

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;
Copier après la connexion

ou dans 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
Copier après la connexion

Cette modification garantit que nous regroupons de manière appropriée les résultats et appliquons les critères de filtrage nécessaires pour récupérer les offres souhaitées qui incluent les sports spécifiés.

Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

source:php.cn
Déclaration de ce site Web
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn
Tutoriels populaires
Plus>
Derniers téléchargements
Plus>
effets Web
Code source du site Web
Matériel du site Web
Modèle frontal