Pregunta Cómo ejecutar una actualización raw sql con enlace dinámico en rieles


Quiero ejecutar una actualización raw sql como a continuación:

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

Este SQL será ejecutado por ActiveRecord::Base.connection.execute, pero no sé cómo pasar los valores del parámetro dinámico en el método.

¿Podría alguien ayudarme con eso?


75
2017-12-19 13:04


origen


Respuestas:


No parece que la API de Rails exponga los métodos para hacer esto genéricamente. Puede intentar acceder a la conexión subyacente y utilizar sus métodos, p. para MySQL:

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

No estoy seguro si hay otras ramificaciones para hacer esto (conexiones dejadas abiertas, etc.). Me gustaría rastrear el código de Rails para una actualización normal para ver lo que está haciendo aparte de la consulta real.

El uso de consultas preparadas puede ahorrarle una pequeña cantidad de tiempo en la base de datos, pero a menos que esté haciendo esto un millón de veces seguidas, probablemente será mejor que solo cree la actualización con la sustitución normal de Ruby, p.

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

o usando ActiveRecord como dijeron los comentaristas.


79
2017-12-19 18:54



ActiveRecord::Base.connection tiene un quote método que toma un valor de cadena (y opcionalmente el objeto columna). Entonces puedes decir esto:

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

Tenga en cuenta que si está en una migración de Rails o un objeto ActiveRecord puede acortarlo a:

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

ACTUALIZAR: Como señala @kolen, debes usar exec_update en lugar. Esto manejará las citas por usted y también evitará la pérdida de memoria. La firma funciona de manera un poco diferente:

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

Aquí el último parámetro es una matriz de tuplas que representan parámetros de enlace. En cada tupla, la primera entrada es el tipo de columna y el segundo es el valor. Puedes dar nil para el tipo de columna y Rails por lo general hará lo correcto.

También hay exec_query, exec_inserty exec_deletedependiendo de lo que necesites


20
2017-07-01 23:01



Deberías usar algo como:

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

Eso serviría. Utilizando el ActiveRecord :: Base # send método para invocar el sanitize_sql_for_assignment hace que el Ruby (al menos la versión 1.8.7) omita el hecho de que sanitize_sql_for_assignment es en realidad un método protegido


4
2018-05-15 03:12



En algún momento sería mejor utilizar el nombre de la clase principal en lugar del nombre de la tabla:

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

Por ejemplo, clase base "Persona", subclases (y tablas de bases de datos) "Cliente" y "Vendedor" En lugar de usar:

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

Puede usar el objeto de la clase base de esta manera:

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

2
2017-11-29 20:58



Necesitaba usar sql sin procesar porque no logré que Composite_primary_keys funcione con activerecord 2.3.8. Entonces, para acceder a la tabla sqlserver 2000 con una clave primaria compuesta, se requería sql en bruto.

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

Si hay una mejor solución disponible, por favor comparta.


-8
2018-04-25 18:06



En Rails 3.1, debe usar la interfaz de consulta:

  • nuevo (atributos)
  • crear (atributos)
  • crear! (atributos)
  • find (id_or_array)
  • destroy (id_or_array)
  • destruye todo
  • eliminar (id_or_array)
  • eliminar todos
  • actualización (ids, actualizaciones)
  • update_all (actualizaciones)
  • existe?

update y update_all son la operación que necesitas.

Ver detalles aquí: http://m.onkey.org/active-record-query-interface


-13
2017-11-11 09:40