Подтвердить что ты не робот

Как выполнить необработанное обновление sql с динамическим привязкой в ​​рельсах

Я хочу выполнить одно обновление raw sql, как показано ниже:

update table set f1=? where f2=? and f3=?

Этот SQL будет выполняться ActiveRecord::Base.connection.execute, но я не знаю, как передать значения динамических параметров в метод.

Может ли кто-нибудь мне помочь?

4b9b3361

Ответ 1

Не похоже, что Rails API предоставляет методы для этого в целом. Вы можете попробовать получить доступ к базовому соединению и использовать его методы, например. для MySQL:

st = ActiveRecord::Base.connection.raw_connection.prepare("update table set f1=? where f2=? and f3=?")
st.execute(f1, f2, f3)
st.close

Я не уверен, есть ли другие последствия для этого (соединения остаются открытыми и т.д.). Я бы проследил код Rails для нормального обновления, чтобы увидеть, что он делает, помимо фактического запроса.

Использование подготовленных запросов может сэкономить вам небольшое количество времени в базе данных, но если вы делаете это миллион раз подряд, вам, вероятно, будет лучше просто создать обновление с обычной заменой Ruby, например.

ActiveRecord::Base.connection.execute("update table set f1=#{ActiveRecord::Base.sanitize(f1)}")

или используя ActiveRecord, как отмечали комментаторы.

Ответ 2

ActiveRecord::Base.connection имеет метод quote, который принимает строковое значение (и необязательно объект столбца). Поэтому вы можете сказать следующее:

ActiveRecord::Base.connection.execute(<<-EOQ)
  UPDATE  foo
  SET     bar = #{ActiveRecord::Base.connection.quote(baz)}
EOQ

Обратите внимание, что если вы используете миграцию Rails или объект ActiveRecord, вы можете сократить ее до:

connection.execute(<<-EOQ)
  UPDATE  foo
  SET     bar = #{connection.quote(baz)}
EOQ

Ответ 3

Вы должны просто использовать что-то вроде:

YourModel.update_all(
  ActiveRecord::Base.send(:sanitize_sql_for_assignment, {:value => "'wow'"})
)

Это сделало бы трюк. Использование метода ActiveRecord:: Base # send для вызова sanitize_sql_for_assignment делает Ruby (по крайней мере, версию 1.8.7) пропустить тот факт, что sanitize_sql_for_assignment strong > - фактически защищенный метод.

Ответ 4

Когда-нибудь было бы лучше использовать имя родительского класса вместо имени таблицы:

# Refers to the current class
self.class.unscoped.where(self.class.primary_key => id).update_all(created _at: timestamp)

Например, базовый класс "Человек", подклассы (и таблицы базы данных) "Клиент" и "Продавец", Вместо этого используйте:

Client.where(self.class.primary_key => id).update_all(created _at: timestamp)
Seller.where(self.class.primary_key => id).update_all(created _at: timestamp)

Вы можете использовать объект базового класса следующим образом:

person.class.unscoped.where(self.class.primary_key => id).update_all(created _at: timestamp)

Ответ 5

Мне нужно было использовать raw sql, потому что мне не удалось получить составные_примары_функции для работы с activerecord 2.3.8. Поэтому для доступа к таблице sqlserver 2000 с составным первичным ключом требуется необработанный sql.

sql = "update [db].[dbo].[#{Contacts.table_name}] " +
      "set [COLUMN] = 0 " +
      "where [CLIENT_ID] = '#{contact.CLIENT_ID}' and CONTACT_ID = '#{contact.CONTACT_ID}'"
st = ActiveRecord::Base.connection.raw_connection.prepare(sql)
st.execute

Если доступно лучшее решение, поделитесь им.

Ответ 6

В Rails 3.1 вы должны использовать интерфейс запроса:

  • новый (атрибуты)
  • create (attributes)
  • создать! (Атрибуты)
  • find (id_or_array)
  • destroy (id_or_array)
  • destroy_all
  • delete (id_or_array)
  • delete_all
  • обновление (ids, updates)
  • update_all (обновления)
  • существует?

update и update_all - необходимая операция.

Подробнее см.: http://m.onkey.org/active-record-query-interface