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


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

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

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

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

6 76

6 ответов:

не похоже, что 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, как сказали комментаторы.

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

обновление: как указывает @kolen, вы должны использовать exec_update вместо. Это будет обрабатывать цитирование для вас, а также избежать утечки памяти. Подпись работает немного по-другому хотя:

connection.exec_update(<<-EOQ, "SQL", [[nil, baz]])
  UPDATE  foo
  SET     bar = 
EOQ

здесь последний параметр представляет собой массив кортежей, представляющих параметров привязки. В каждом кортеже первая запись - это тип столбца, а вторая-значение. Вы можете дать nil для типа столбца и рельсов обычно будет делать правильную вещь, хотя.

также exec_query,exec_insert и exec_delete в зависимости от того, что вам нужно.

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

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 на самом деле защищенного метода.

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

# 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)

Мне нужно было использовать raw sql, потому что я не смог получить composite_primary_keys для работы с 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

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

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

  • новый(атрибуты)
  • создать(атрибуты)
  • создать!(атрибуты)
  • найти(id_or_array)
  • уничтожить(id_or_array)
  • destroy_all
  • удалить(id_or_array)
  • delete_all
  • обновление(идентификаторы, обновления)
  • update_all, а(обновления)
  • ?

update и update_all являются операция вам нужна.

подробности смотрите здесь:http://m.onkey.org/active-record-query-interface