繁体   English   中英

原始SQL请求中的Rails 4字符串插值

[英]Rails 4 string interpolation in raw SQL request

在没有插值的情况下重写此查询的最佳方法是什么?

def case_joins(type)
  subquery = <<-SQL.squish
    SELECT id FROM cases c2
    WHERE c2.title_id = titles.id AND c2.value = 0 AND c2.type = '#{type}'
    ORDER BY c2.created_at DESC LIMIT 1       
  SQL
  "LEFT OUTER JOIN cases ON cases.title_id = titles.id AND cases.value = 0 AND cases.type = '#{type}' AND cases.id = (#{subquery})"
end

我假设您要避免插入变量,因为它对SQL注入开放是危险的。 我只是简单地加入从子查询中选择的案例,而不是将子查询放入WHERE条件中。 这确实涉及插值,但仅涉及AR生成的SQL。 我还将它作为一个范围来实现,以利用AR范围链:

class Title < ActiveRecord::Base
  def self.case_joins(type)
    case_query = Case.from("cases c").where(c: {title_id: title_id, value: 0, type: type}).order('c.created_at DESC').limit(1)
    joins("LEFT OUTER JOIN (#{case_query.to_sql}) cases ON cases.title_id = titles.id")
  end
end

这样,您可以将范围链接到其他人,如下所示:

Title.where(attribute1: value1).case_joins("typeA")

(注意,删除了外部SELECT多余的WHERE条件。)

很难推断出你的代码的其余部分是什么样的,但是我认为在你的调用堆栈中进一步使用了titles

如果您使用ActiveRecord而不是本机SQL,您可以执行以下操作:

def case_joins(scope, title_id, type)
  ids = Case.where(title_id: title_id, value: 0, type: type)
             .order('created_at desc').limit(1).pluck(:id)

  scope.joins('left outer join cases on cases.title_id = titles.id')
             .where(value: 0, type: type, id: ids)
end

这里的scope是您正在修改的当前AR查询。

这是我的头脑,所以我不确定上面的AR语法是否正确,但它确实避免了插入SQL并使用范围。

说实话,它并不比原生SQL更可读,因此YMMV。 它至少意味着(除了连接之外)你没有在代码中编码SQL。

以下是@ eirikir答案的修改,其作用与所讨论的方法相同。

def case_joins(type)
  case_query = Case.from("cases c").where('c.title_id = titles.id AND c.value = 0 AND c.type = ?', type).order('c.created_at DESC').select(:id).limit(1)
 "LEFT OUTER JOIN cases ON cases.title_id = titles.id AND cases.id = (#{case_query.to_sql})"
end

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM