Как сделать update_all на основе подзапроса в Rails - PullRequest
0 голосов
/ 06 сентября 2018

Я пытаюсь добиться чего-то довольно простого в PostgreSQL способом Rails.

Допустим, у вас есть модель User с 3 столбцами 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   ...

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 голосов
/ 21 сентября 2018

Да, у 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")

Надеюсь, это поможет ...

...