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