【问题标题】:Rails 4 ActiveRecord Query: bind variables in order clauseRails 4 ActiveRecord Query:在 order 子句中绑定变量
【发布时间】:2015-01-22 20:25:37
【问题描述】:

我正在尝试在我的 mysql 查询中内置动态顺序,以便将某些匹配项放在顶部。

Ticket.where(
  "id LIKE :search || name LIKE :search", 
  {search: "%#{params[:search]}]%"}
).order(
  "id = :exact DESC, name = :exact DESC, id LIKE :search DESC, name LIKE :search DESC", 
  {exact: params[:search], search: "%#{params[:search]}%"}
)

假设 params[:search] = 'search_value',查询应该这样结束:

SELECT * FROM tickets
WHERE id LIKE "%search_value%" || name LIKE "%search_value%"
ORDER BY id = 'search_value' DESC, name = 'search_value' DESC, id LIKE "%search_value%" DESC, name LIKE "%search_value%" DESC;

每当我这样做时,我都会从 ActiveRecord::QueryMethods.validate_order_args 收到一个错误,说方向应该是 :asc 或 :desc。

除了手动清理搜索然后将其直接插入到订单字符串中,有没有办法让它像 where 子句的绑定变量一样工作?

【问题讨论】:

  • 您的“order by”部分不正确。 “order by”不能包含等号!将 search_value 放入“order by”部分是没有意义的。请参阅 MySQL 参考:dev.mysql.com/doc/refman/5.7/en/order-by-optimization.html
  • 这绝对不正确,equals 将返回 1 或 0。因此,根据搜索评估最终结果的方式,执行为“ORDER BY 1 DESC, 0 DESC, 1 DESC, 0 DESC” on每个记录的基础。只需尝试执行“select * from any order by 10 = id DESC”,它将在顶部返回 id 10,然后是其他所有内容。
  • 好吧,我直到现在才知道。谢谢你的提示。 link

标签: mysql ruby-on-rails-4 rails-activerecord


【解决方案1】:

所以经过一番挖掘,我想我已经找到了解决这个问题的方法,尽管我希望 rails 有更好的方法。

我已将其包含在我的 Rails 项目中

class ActiveRecord::Base
  def self.corder *array
    statement = array.shift
    while (i=array.shift).present?
      case i
      when Hash
        i.each do |k,v|
          statement.gsub!(':' + k.to_s, ActiveRecord::Base.sanitize(v))
        end
      when String
        statement.sub!('?', ActiveRecord::Base.sanitize(i))
      else
        raise "Unknown type: #{i} -- #{i.class}"
      end
    end
    self.order(statement)
  end

  def corder *array
    statement = array.shift
    while (i=array.shift).present?
      case i
      when Hash
        i.each do |k,v|
          statement.gsub!(':' + k.to_s, sanitize(v))
        end
      when String
        statement.sub!('?', sanitize(i))
      else
        raise "Unknown type: #{i} -- #{i.class}"
      end
    end
    self.order!(statement)
  end
end

就我的目的而言,尽管它可以很容易地扩展,但它非常有效。这两个是完全重复的(在类和实例上需要它的简单解决方案)。

此时你可以:

Model.where(
  'id LIKE :search || name LIKE :search', 
  {search: "%#{params[:search]}%"}
).order(
  'id = :exact DESC, name = :exact DESC, id LIKE :rough DESC, name LIKE :rough DESC', 
  {exact: params[:search], rough: "%#{params[:search]}%"}
)

SQL 假设 params[:search] == 'ibm':

SELECT * FROM model WHERE id LIKE '%ibm%' || name LIKE '%ibm%' ORDER BY id = 'ibm' DESC, name = 'ibm' DESC, id LIKE '%ibm%' DESC, name LIKE '%ibm%' DESC;

或者“?”绑定变量也可以,例如:

Model.where(
  'id LIKE ? || name LIKE ?', 
  "%#{params[:search]}%", "%#{params[:search]}%"
).order(
  'id = ? DESC, name = ? DESC, id LIKE ? DESC, name LIKE ? DESC', 
  params[:search], params[:search], "%#{params[:search]}%", "%#{params[:search]}%"
)

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2011-02-06
    • 1970-01-01
    • 1970-01-01
    • 2012-11-17
    • 1970-01-01
    • 2012-04-09
    • 2011-06-25
    • 1970-01-01
    相关资源
    最近更新 更多