Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/ruby-on-rails/62.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
SQL where联接集必须包含所有值,但可能包含更多值_Sql_Ruby On Rails_Postgresql_Rails Activerecord_Relational Division - Fatal编程技术网

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