如何基于Rails中的子查询`update_all`

时间:2018-09-06 13:54:37

标签: ruby-on-rails rails-activerecord bulkupdate

我正在尝试以Rails方式在PostgreSQL中实现一些非常简单的事情。

假设您有一个User模型,其中包含3列idcached_segmentcached_step。 假设您已经有一个复杂的查询,该查询可以即时计算segmentquery,并封装在范围User.decorate_with_segment_and_step中。这将返回一个ActiveRecord关系,与User相同,但有3个附加列:

id  cached_segment cached_step segment    step    cache_invalid
1   NULL           NULL        segment_1  step_1  TRUE
2   segment_1      step_2      segment_1  step_2  FALSE
3   ...

我要生成的SQL如下(PostgreSQL风格):

UPDATE users
SET cached_segment = segment_1
    cached_step    = step
FROM (#{User.decorate_with_segment_and_step.to_sql}) decorated_users
WHERE decorated_users.cache_invalid AND decorated_users.id = users.id

理想情况下,我可以做类似的事情

User.
  from(User.decorate_with_segment_and_step, 'decorated_users').
  where(cache_invalid: true).
  update_all('cached_segment = segment, cached_step = step')

根据源代码,我对上面的语句update_all并不走运,只是在构建更新语句时放弃了from子句。

注意:我知道我可以只使用User.connection.execute(my_raw_sql_here),这就是我现在正在做的。目标是坚持使用ActiveRecord。

1 个答案:

答案 0 :(得分:0)

是的,AR有其局限性,但这不是其中之一。假设您正在使用Postgres进行开发,测试和生产等所有工作,那么您的愿望就是:

ActiveRecord::Base.connection.execute("UPDATE users SET cached_segment = segment_1, cached_step = step FROM (#{User.decorate_with_segment_and_step.to_sql}) decorated_users WHERE decorated_users.cache_invalid AND decorated_users.id = users.id")

希望有帮助...