【问题标题】:AREL: writing complex update statements with from clauseAREL:使用 from 子句编写复杂的更新语句
【发布时间】:2014-03-19 09:46:37
【问题描述】:

我尝试寻找使用Arel::UpdateManager 来形成带有from 子句的更新语句的示例(如UPDATE t SET t.itty = "b" FROM .... WHERE ...),但找不到。在我看来,Arel::UpdateManager 在初始化时设置了主引擎,并允许设置要更新的各种字段和值。实际上有办法做到这一点吗?

另一个问题是找出如何将 Postgres posix 正则表达式匹配表达为 ARel,但现在这可能是不可能的。

【问题讨论】:

    标签: postgresql activerecord sql-update arel


    【解决方案1】:

    据我所知,arel gem 的当前版本不支持 查询的 FROM 关键字。您可以只使用 SETWHERE 关键字生成查询,例如:

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

    对于units 表,将值从field2 复制到field1 的代码如下:

    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 作为参数传递给方法。然后我们需要在生成的SQL请求中添加FROM关键字,我们只有在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)
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-05-13
      • 2010-12-29
      相关资源
      最近更新 更多