簡體   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