2014-03-19 83 views
1
編寫複雜的更新語句

我嘗試尋找一個使用Arel::UpdateManager與from子句形成更新語句的示例(如UPDATE t SET t.itty = "b" FROM .... WHERE ...),couldn.t找到任何。我看到它的方式,Arel::UpdateManager在初始化時設置主引擎,並允許設置更新的各個字段和值。有沒有辦法做到這一點?另一種方法是找出如何將Postgres posix正則表達式匹配到ARel中,但現在這可能是不可能的。AREL:用條款

回答

1

據我看到的當前版本arel gem不支持關鍵字爲查詢。您可以生成使用SET查詢和WHERE關鍵字只有一樣:

UPDATE t SET t.itty = "b" WHERE ... 

和代碼,拷貝從field2field1units表中的值,將是這樣的:

relation = Unit.all 
um = Arel::UpdateManager.new(relation.engine) 
um.table(relation.table) 
um.ast.wheres = relation.wheres.to_a 
um.set(Arel::Nodes::SqlLiteral.new('field1 = "field2"')) 
ActiveRecord::Base.connection.execute(um.to_sql) 

準確地說,您可以使用其他方法更新關係。因此,我們創建Arel的UpdateManager,爲其分配表where子句以及要設置的值。將shell作爲參數傳遞給方法。然後,我們需要將FROM關鍵字添加到生成的SQL請求中,只有當我們有權訪問由UPDATE子句本身指定的外部表時,纔會添加它。最後我們執行查詢。所以我們得到:

def update_relation!(relation, values) 
    um = Arel::UpdateManager.new(relation.engine) 
    um.table(relation.table) 
    um.ast.wheres = relation.wheres.to_a 
    um.set(values) 
    sql = um.to_sql 

    # appends FROM field to the query if needed 
    m = sql.match(/WHERE/) 
    tables = relation.arel.source.to_a.select {|v| v.class == Arel::Table }.map(&:name).uniq 
    tables.shift 
    sql.insert(m.begin(0), "FROM #{tables.join(",")} ") if m && !tables.empty? 

    # executes the query 
    ActiveRecord::Base.connection.execute(sql) 
end 

的可以發出的關係最新情況:

values = Arel::Nodes::SqlLiteral.new('field1 = "field2", field2 = NULL') 
relation = Unit.not_rejected.where(Unit.arel_table[:field2].not_eq(nil)) 
update_relation!(relation, values)