Ruby on rails 原始SQL请求中的Rails 4字符串插值
在没有插值的情况下重写此查询的最佳方法是什么Ruby on rails 原始SQL请求中的Rails 4字符串插值,ruby-on-rails,ruby,postgresql,ruby-on-rails-4,Ruby On Rails,Ruby,Postgresql,Ruby On Rails 4,在没有插值的情况下重写此查询的最佳方法是什么 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 JOI
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
很难推断代码的其余部分是什么样子的,但我假设标题正在调用堆栈更上层的查询中使用 如果要使用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
这里的范围是您正在修改的当前AR查询
这是我不知道的,所以我不确定上面的AR语法是否正确,但它确实避免了插入SQL的需要,并且还使用了范围
不过,老实说,它的可读性并不比本机SQL强多少,所以。这至少意味着除了join之外,您没有在代码中编码SQL。我假设您希望避免变量插值,这是危险的,因为它对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
注意,删除了外部选择中多余的WHERE条件。这里是对@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
这看起来不错,但是我需要为子查询case\u query中的表指定一个不同的名称。我可以用WHERE来做这个吗?@Pav31我已经在子查询上用别名编辑了答案-你只需要使用from范围,然后编辑WHERE散列来匹配。谢谢!它起作用了,尽管我需要对你的方法做一些小改动,在limit1'之前添加select:id,并删除self',因为我在模型之外声明它。很好,如果它对你起作用,您可以继续并接受答案吗?如果您愿意使用.select:id而不是.pulk:id,那么到数据库服务器的往返只有一次,而不是两次;如果您有一个非常大的数据集,这可能是您唯一的选择。
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