SQL where联接集必须包含所有值,但可能包含更多值
我有三个表SQL where联接集必须包含所有值,但可能包含更多值,sql,ruby-on-rails,postgresql,rails-activerecord,relational-division,Sql,Ruby On Rails,Postgresql,Rails Activerecord,Relational Division,我有三个表提供,运动和join表提供体育 class Offer < ActiveRecord::Base has_and_belongs_to_many :sports end class Sport < ActiveRecord::Base has_and_belongs_to_many :offers end 考虑到数组[“Bodyboarding”,“Surfing”]我想得到中等和所有但不是灯光 我尝试了类似的方法,但结果中没有行: Offer.joins(:s
提供
,运动
和join表提供体育
class Offer < ActiveRecord::Base
has_and_belongs_to_many :sports
end
class Sport < ActiveRecord::Base
has_and_belongs_to_many :offers
end
考虑到数组[“Bodyboarding”,“Surfing”]
我想得到中等和所有但不是灯光
我尝试了类似的方法,但结果中没有行:
Offer.joins(:sports)
.where(sports: { name: ["Bodyboarding", "Surfing"] })
.group("sports.name")
.having("COUNT(distinct sports.name) = 2")
转换为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;
一个ActiveRecord的答案会很好,但我只接受SQL,最好是兼容Postgres的
数据:
分组依据offer.id
,而不是sports.name
(或sports.id
):
假设典型实现:
offer.id
和sports.id
被定义为主键
sports.name
的定义是唯一的
中的(运动id,优惠id)
定义为唯一(或PK)
计数中不需要DISTINCT
。而且,count(*)
甚至更便宜一点
与可能的技术库相关的答案:
由@max(OP)添加-这是在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
class Offer
按提供.id
分组,而不是按运动.name
(或运动.id
):
假设典型实现:
offer.id
和sports.id
被定义为主键
sports.name
的定义是唯一的
中的(运动id,优惠id)
定义为唯一(或PK)
计数中不需要DISTINCT
。而且,count(*)
甚至更便宜一点
与可能的技术库相关的答案:
由@max(OP)添加-这是在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
class Offer
一种方法是使用数组和array\u agg
聚合函数
SELECT "offers".*, array_agg("sports"."name") as spnames
FROM "offers"
INNER JOIN "offers_sports" ON "offers_sports"."offer_id" = "offers"."id"
INNER JOIN "sports" ON "sports"."id" = "offers_sports"."sport_id"
GROUP BY "offers"."id" HAVING array_agg("sports"."name")::text[] @> ARRAY['Bodyboarding','Surfing']::text[];
返回:
id | name | spnames
----+--------+---------------------------------------------------
2 | medium | {Yoga,Bodyboarding,Surfing}
3 | all | {Yoga,Bodyboarding,Surfing,Parasailing,Skydiving}
(2 rows)
@>
运算符意味着左侧的数组必须包含右侧数组中的所有元素,但可能包含更多元素。spnames
列仅用于显示,但您可以安全地将其删除
有两件事你必须非常注意
即使使用Postgres 9.4(我还没有尝试过9.5),用于比较数组的类型转换也是草率的,并且经常出错,告诉您无法找到将它们转换为可比较值的方法,因此您可以在示例中看到,我使用::text[]
手动转换了两侧
我不知道Ruby和RoR框架对数组参数的支持程度如何,因此您可能最终不得不手动转义字符串(如果用户输入),并使用array[]
语法形成数组
一种方法是使用数组和array\u agg
aggregate函数
SELECT "offers".*, array_agg("sports"."name") as spnames
FROM "offers"
INNER JOIN "offers_sports" ON "offers_sports"."offer_id" = "offers"."id"
INNER JOIN "sports" ON "sports"."id" = "offers_sports"."sport_id"
GROUP BY "offers"."id" HAVING array_agg("sports"."name")::text[] @> ARRAY['Bodyboarding','Surfing']::text[];
返回:
id | name | spnames
----+--------+---------------------------------------------------
2 | medium | {Yoga,Bodyboarding,Surfing}
3 | all | {Yoga,Bodyboarding,Surfing,Parasailing,Skydiving}
(2 rows)
@>
运算符意味着左侧的数组必须包含右侧数组中的所有元素,但可能包含更多元素。spnames
列仅用于显示,但您可以安全地将其删除
有两件事你必须非常注意
即使使用Postgres 9.4(我还没有尝试过9.5),用于比较数组的类型转换也是草率的,并且经常出错,告诉您无法找到将它们转换为可比较值的方法,因此您可以在示例中看到,我使用::text[]
手动转换了两侧
我不知道Ruby和RoR框架对数组参数的支持程度如何,因此您可能最终不得不手动转义字符串(如果用户输入),并使用array[]
语法形成数组
SQL有效吗?它看起来正确。它返回0行@Gordonlinoff您就快到了:按“offers”字段分组(用显式字段名替换*并重复分组中的字段名)。您现在正在按sports.name进行分组,当然,每个sports.name的sports.name的不同计数始终为1。@HenkKok仍然提供0行:SELECT offers.name、offers.id、sports.id从“offers\u sports”上的“offers”internal JOIN“offers\u sports”中选择offers.name、offers.id、sports.id。“offers\u id”在哪里按offers.name、offers.id、sports.name计数的(‘Bodyboarding’、‘Surfing’)组中的“sports.”name(不同的sports.name)=2
这是因为您仍然将sports.name包含在group by中,该列必须从group by中删除;此外,还必须从SELECT子句中删除sports.id。如果您需要最终结果中的报价和体育项目,请首先在报价上进行选择(链接到所有2项体育项目)然后使用该选择作为内联视图加入运动。SQL有效吗?它看起来正确。它返回0行。@GordonLinoff您就快到了:按“提供”字段分组(用显式字段名替换*并重复分组中的字段名)。您现在正在按sports.name进行分组,当然,每个sports.name的sports.name的不同计数始终为1。@HenkKok仍然提供0行:从“offers\u sports”上的“offers”内部加入“offers\u sports”。“offer\u id”=“offers”;“id”内部加入“sports”;“offers\u sports”;“sport\u id”在哪里运动(‘Bodyboarding’、‘Surfing’)组中的“name”按offers.name、offers.id、sports.name包含C