将自定义sql添加到finder条件的问题

时间:2009-03-11 00:40:13

标签: sql mysql ruby-on-rails activerecord

我正在尝试将以下自定义sql添加到finder条件中并且有一些不太正确的事情..我不是一个sql专家但是这个问题与一个朋友一起解决了..(但他们并不熟悉rubyonrails或activerecord或finder)

status_search = "select p.*
               from policies p
               where exists
                   (select 0 from status_changes sc
                   where sc.policy_id = p.id
                   and sc.status_id = '"+search[:status_id].to_s+"'
                   and sc.created_at between "+status_date_start.to_s+" and "+status_date_end.to_s+")
               or exists
                   (select 0 from status_changes sc
                   where sc.created_at =
                       (select max(sc2.created_at)
                       from status_changes sc2
                       where sc2.policy_id = p.id
                       and sc2.created_at < "+status_date_start.to_s+")
                   and sc.status_id = '"+search[:status_id].to_s+"'
                   and sc.policy_id = p.id)" unless search[:status_id].blank?

我的发现声明:    Policy.find(:所有,:包括=&GT; [{:客户=&GT; [:剂:SOURCE_ID,:source_code]},{:status_changes =&GT;:状态}],       :条件=&GT; [status_search])

我在日志中收到此错误消息:

ActiveRecord::StatementInvalid (Mysql::Error: Operand should contain 1 column(s): SELECT DISTINCT `policies`.id FROM `policies`  LEFT OUTER JOIN `clients` ON `clients`.id = `policies`.client_id WHERE ((((policies.created_at BETWEEN '2009-01-01' AND '2009-03-10' OR policies.created_at = '2009-01-01' OR policies.created_at = '2009-03-10')))) AND (select p.*
               from policies p
               where exists
                   (select 0 from status_changes sc
                   where sc.policy_id = p.id
                   and sc.status_id = '2'
                   and sc.created_at between 2009-03-10 and 2009-03-10)
               or exists
                   (select 0 from status_changes sc
                   where sc.created_at =
                       (select max(sc2.created_at)
                       from status_changes sc2
                       where sc2.policy_id = p.id
                       and sc2.created_at < 2009-03-10)
                   and sc.status_id = '2'
                   and sc.policy_id = p.id))  ORDER BY clients.created_at DESC LIMIT 0, 25):

这里的主要故障是什么 - 它为什么抱怨这些列?

2 个答案:

答案 0 :(得分:1)

condition修饰符期望一个条件(例如一个可以放在where子句中的布尔表达式),并且你传递一个完整的查询(一个select语句)。

看起来好像你想在这里一次做太多,并且应该把它分解成更小的步骤。一些建议:

  • 将查询与find_by_sql一起使用,不要弄乱条件。
  • 使用导轨查找器并过滤导轨代码中的记录

另外,请注意,如果像status_date_start这样的值可以来自用户,则以这种方式构建查询并不安全。查看“sql注入攻击”以查看问题所在,并阅读rails文档&amp; find_by_sql的示例,了解如何避免它们。

答案 1 :(得分:0)

好吧,我已经设法重新调整了这个,所以它对条件修饰符更友好,我认为它正在正确地执行sql查询..但是,当我尝试列出当前状态时,它返回的策略( policy.status_change.last.status)它被设置为查询中使用的相同状态 - 这是不正确的

这是我更新的条件字符串..

status_search = "status_changes.created_at between ? and ? and status_changes.status_id = ?) or 
      (status_changes.created_at = (SELECT MAX(sc2.created_at) FROM status_changes sc2 
              WHERE sc2.policy_id = policies.id and sc2.created_at < ?) and status_changes.status_id = ?"

有什么显而易见的东西,一旦在查询中找到一个,就不会返回所有剩余的相关状态变化吗?

这是更新后的发现..

Policy.find(:all,:include=>[{:client=>[:agent,:source_id,:source_code]},:status_changes],
  :conditions=>[status_search,status_date_start,status_date_end,search[:status_id].to_s,status_date_start,search[:status_id].to_s])