SQL:WHERE Joined Set 必须包含所有值,但可能包含更多
在 SQL 中,“WHERE JOINED SET”子句确保连接表在其结果集中包含特定值。但是,连接表还可能包含不属于条件的附加值。这个概念在实践中实施起来可能具有挑战性,特别是在确定条件中包含哪些值时。
考虑以下示例:
场景:
你有三个表:offer、sports 和 Offers_sports,分别代表 Offers、sports 以及它们之间的关系。您想要选择包含给定运动名称数组的优惠。优惠必须包含所有运动项目,但也可能包括其他运动项目。
数据:
offers | id | name | | --- | ---- | | 1 | light | | 2 | medium | | 3 | all | | 4 | extreme | sports | id | name | | --- | ---- | | 1 | Yoga | | 2 | Bodyboarding | | 3 | Surfing | | 4 | Parasailing | | 5 | Skydiving | offers_sports | offer_id | sport_id | | --- | ---- | | 1 | 1 | | 1 | 2 | | 2 | 1 | | 2 | 2 | | 2 | 3 | | 3 | 1 | | 3 | 2 | | 3 | 3 | | 3 | 4 | | 3 | 5 | | 4 | 3 | | 4 | 4 | | 4 | 5 |
期望结果:
给定数组 ["Bodyboarding", "Surfing"],查询应返回优惠媒介以及所有这些,因为它们包含两种指定的运动。优惠灯不应退回,因为它不包含这两种运动。
不正确的查询:
以下查询,按运动名称分组并确保恰好有两个每项优惠均包含体育运动,不退货结果:
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;
解决方案:
正确的查询按优惠 ID 而不是运动名称进行分组,并使用 COUNT( 检查每个优惠中包含的不同运动的数量DISTINCT):
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;
此查询将返回报价媒介和全部,因为它们都包含指定的体育。
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(DISTINCT sports.name) = ?", sport_names.size) end end
以上是如何在 SQL 中选择包含所有给定体育项目(但可能更多)的报价?的详细内容。更多信息请关注PHP中文网其他相关文章!