Rails:has_many关联中的AND运算符

时间:2016-04-10 01:57:33

标签: ruby-on-rails activerecord

我的关系是Client可以有很多ClientJobs。我希望能够找到同时执行Job aJob b的客户。我使用了3个选择框,因此我可以选择最多三个作业进行选择。选择框从数据库中填充。

我知道如何使用下面的查询测试1个作业。但我需要一种方法来使用AND运算符来测试该客户端是否存在这两个作业。

@clients = Client.includes("client_jobs").where(
  client_jobs: { job_name: params[:job1]})

不幸的是,按照下面的操作很容易进行IN操作,但我认为AND的语法应该类似......我希望

@lients = Client.includes("client_jobs").where(
  client_jobs: { job_name: [params[:job1], params[:job2]]})

编辑:从下面的答案中发布命中数据库的sql语句

Core Load (0.6ms) SELECT `clients`.* FROM `clients`
CoreStatistic Load (1.9ms)  SELECT `client_jobs`.* FROM `client_jobs`
  WHERE `client_jobs `.`client_id` IN (1, 2, 3, 4, 5, 6, 7, 8, 9, 10,........)

第二个查询遍历数据库中的每个client_job。它从未针对params[:job1], params[:job2]等进行测试。因此@clients会导致nil崩溃我的视图模板

(undefined method `map' for nil:NilClass

1 个答案:

答案 0 :(得分:3)

在我看来,自我加入的更好方法是简单地加入ClientJobs,然后使用GROUP BYHAVING子句过滤掉那些与给定关联完全匹配的记录记录。

performed_jobs = %w(job job2 job3)
Client.joins(:client_jobs).
       where(client_jobs: { job_name: performed_jobs }).
       group("clients.id").
       having("count(*) = #{performed_jobs.count}")

让我们来看看这个问题:

  • 前两个条款将ClientJob加入Client并过滤掉那些定义的三个作业中的任何一个(它使用IN子句)< / LI>
  • 接下来,group我们Client.id这些已加入的记录,以便我们让客户回来
  • 最后,having子句确保我们只返回那些加入了3 ClientJob条记录的客户端,即只有那些定义了所有三个客户端作业的客户

HAVING(COUNT(*) = ...)的诀窍是将IN子句(实际上是OR - 选项列表)转换为&#34;必须拥有所有这些&#34 ;子句。