如何基于Rails中的子查询来"update_all"

Mat*_*eer 6 ruby-on-rails rails-activerecord bulkupdate

我试图在PostgreSQL中实现一些非常简单的Rails方式.

假设你有一个User3列模型id,cached_segment,cached_step.假设您已经有一个复杂的查询,它可以计算segment并动态地query封装在一个范围内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   ...
Run Code Online (Sandbox Code Playgroud)

我想生成的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
Run Code Online (Sandbox Code Playgroud)

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

User.
  from(User.decorate_with_segment_and_step, 'decorated_users').
  where(cache_invalid: true).
  update_all('cached_segment = segment, cached_step = step')
Run Code Online (Sandbox Code Playgroud)

我对上面的语句没有好运update_all,根据源代码,只是from在构建update语句时丢弃该子句.

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

hd1*_*hd1 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")
Run Code Online (Sandbox Code Playgroud)

希望能帮助到你...