[英]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.