ActiveRecord has_many有多个条件

时间:2015-11-18 20:16:53

标签: sql ruby-on-rails activerecord

我试图通过检查它的几个关系来找到一个对象。

Loan.joins(:credit_memo_attributes)
    .where(credit_memo_attributes: {name: 'pr2_gtx1_y', value: '2014'})
    .where(credit_memo_attributes: {name: 'pr1_gtx1_y', value: '2013'})
    .where(credit_memo_attributes: {name: 'tx1_y', value: '2014'})

调用to_sql就可以了:

"SELECT `loans`.* FROM `loans` INNER JOIN `credit_memo_attributes` 
  ON `credit_memo_attributes`.`loan_id` = `loans`.`id` 
  WHERE `credit_memo_attributes`.`name` = 'pr2_gtx1_y' AND `credit_memo_attributes`.`value` = '2014' 
    AND `credit_memo_attributes`.`name` = 'pr1_gtx1_y' AND `credit_memo_attributes`.`value` = '2013' 
    AND `credit_memo_attributes`.`name` = 'tx1_y' AND `credit_memo_attributes`.`value` = '2014'"

所以,我正在检查具有所有这些属性的credit_memo_attributes的贷款。我知道我们的20,000笔贷款中至少有一笔符合此条件,但此查询返回一个空集。如果我只使用where子句中的一个,它会返回几个,正如我所期望的那样,但是一旦我再添加一个,它就是空的。

知道我哪里出错了?

3 个答案:

答案 0 :(得分:1)

更新

根据评论我相信您希望在您的条件中加入多个联接。你可以这样做:

attr_1 = {name: 'pr2_gtx1_y', value: '2014'}
attr_2 = {name: 'pr1_gtx1_y', value: '2013'}
attr_3 = {name: 'tx1_y', value: '2014'}

Loan.something_cool(attr_1, attr_2, attr_3)

class Loan < ActiveRecord::Base
...
def self.something_cool(attr_1, attr_2, attr_3)
  joins(sanitize_sql(["INNER JOIN credit_memo_attributes AS cma1 ON cma1.loan_id = loans.id AND cma1.name = :name AND cma1.value = :value", attr_1]))
    .joins(sanitize_sql(["INNER JOIN credit_memo_attributes AS cma2 ON cma2.loan_id = loans.id AND cma2.name = :name AND cma2.value = :value", attr_2]))
    .joins(sanitize_sql(["INNER JOIN credit_memo_attributes AS cma3 ON cma3.loan_id = loans.id AND cma3.name = :name AND cma3.value = :value", attr_3]))

end

如果您查看生成的SQL(包含在您的问题中,谢谢),您将看到所有这些条件正在进行AND运算。没有名称=&#39; pr2_gtx1_y&#39; AND name =&#39; pr1_gtx1_y&#39; (等等)。所以你得到了我期望的结果(没有行)。

答案 1 :(得分:0)

您可以将所有名称和值放入数组中,如id和years,并将其传递到where子句中。 Active Record将查询数组中的所有值。

Loan.joins(:credit_memo_attributes)
    .where(credit_memo_attributes: {name: ids, value: years})

就我个人而言,我仍然在学习积极的记录,在这种担忧中我并不认为积极的记录支持多个where子句。

答案 2 :(得分:0)

请注意SQL版本如何返回您的代码:它使用AND加入要求。

"SELECT `loans`.* FROM `loans` INNER JOIN `credit_memo_attributes` 
  ON `credit_memo_attributes`.`loan_id` = `loans`.`id` 
  WHERE `credit_memo_attributes`.`name` = 'pr2_gtx1_y' AND `credit_memo_attributes`.`value` = '2014' 
    AND `credit_memo_attributes`.`name` = 'pr1_gtx1_y' AND `credit_memo_attributes`.`value` = '2013' 
    AND `credit_memo_attributes`.`name` = 'tx1_y' AND `credit_memo_attributes`.`value` = '2014'"

现在,这几乎是不可能的。 Object.name永远不可能是pr2_gtx1_ypr1_gtx1_ytx1_yvalue属性也是如此。

这里需要的是OR,而不是AND

为此,请尝试将查询更改为以下内容:

Loan.joins(:credit_memo_attributes)
  .where(
    "credit_memo_attributes.name = ? and credit_memo_attributes.value = ?
    OR credit_memo_attributes.names = ? and credit_memo_attributes.value = ?
    OR credit_memo_attributes.name = ? and credit_memo_attributes.value = ?",
    'pr2_gtx1_y', '2014',
    'pr1_gtx1_y', '2013',
    'tx1_y', '2014'
  )