Как выполнить необработанное обновление sql с динамическим привязкой в рельсах
Я хочу выполнить одно обновление raw sql, как показано ниже:
update table set f1=? where f2=? and f3=?
Этот SQL будет выполняться ActiveRecord::Base.connection.execute
, но я не знаю, как передать значения динамических параметров в метод.
Может ли кто-нибудь мне помочь?
Ответы
Ответ 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