¿Existe una forma elegante de hacer un INSERT ... ON DUPLICATE KEY UPDATE
en SQLAlchemy? Me refiero a algo con una sintaxis similar a inserter.insert().execute(list_of_dictionaries)
?SQLAlchemy ACTUALIZACIÓN DE LLAVE DUPLICADA
Respuesta
ON DUPLICATE KEY UPDATE
en la instrucción SQL
Si desea que el SQL generado para incluir realidad ON DUPLICATE KEY UPDATE
, la forma más sencilla consiste en utilizar un decorador @compiles
.
El código (vinculado desde un buen hilo sobre el tema on reddit) para un ejemplo se puede encontrar on github:
from sqlalchemy.ext.compiler import compiles
from sqlalchemy.sql.expression import Insert
@compiles(Insert)
def append_string(insert, compiler, **kw):
s = compiler.visit_insert(insert, **kw)
if 'append_string' in insert.kwargs:
return s + " " + insert.kwargs['append_string']
return s
my_connection.execute(my_table.insert(append_string = 'ON DUPLICATE KEY UPDATE foo=foo'), my_values)
Pero tenga en cuenta que, en este enfoque, usted tiene que crear manualmente el append_string. Probablemente puedas cambiar la función append_string para que cambie automáticamente la cadena de inserción en una inserción con la secuencia 'ON DUPLICATE KEY UPDATE', pero no voy a hacer eso aquí debido a la pereza.
ON DUPLICATE KEY UPDATE
funcionalidad dentro de la ORM
SQLAlchemy no proporciona una interfaz para ON DUPLICATE KEY UPDATE
o MERGE
o cualquier otra funcionalidad similar en su capa ORM. Sin embargo, tiene la función session.merge()
que puede replicar la funcionalidad solo si la clave en cuestión es una clave principal.
session.merge(ModelObject)
primero comprueba si existe una fila con el mismo valor de clave principal enviando una consulta SELECT
(o buscándola localmente). Si lo hace, establece un indicador en algún lugar que indica que ModelObject ya está en la base de datos, y que SQLAlchemy debe usar una consulta UPDATE
. Tenga en cuenta que fusionar es bastante más complicado que esto, pero replica bien la funcionalidad con claves primarias.
Pero, ¿qué ocurre si desea la funcionalidad ON DUPLICATE KEY UPDATE
con una clave no primaria (por ejemplo, otra clave única)? Desafortunadamente, SQLAlchemy no tiene ninguna de esas funciones. En su lugar, debe crear algo que se asemeje al get_or_create()
de Django. Another StackOverflow answer covers it, y solo pegaré una versión de trabajo modificada aquí para su comodidad.
def get_or_create(session, model, defaults=None, **kwargs):
instance = session.query(model).filter_by(**kwargs).first()
if instance:
return instance
else:
params = dict((k, v) for k, v in kwargs.iteritems() if not isinstance(v, ClauseElement))
if defaults:
params.update(defaults)
instance = model(**params)
return instance
Tienes una solución más simple:
from sqlalchemy.ext.compiler import compiles
from sqlalchemy.sql.expression import Insert
@compiles(Insert)
def replace_string(insert, compiler, **kw):
s = compiler.visit_insert(insert, **kw)
s = s.replace("INSERT INTO", "REPLACE INTO")
return s
my_connection.execute(my_table.insert(replace_string=""), my_values)
Ten cuidado. 'REPLACE INTO' y' INSERT ... ON DUPLICATE KEY UPDATE' hacen cosas diferentes. –
En particular, se elimina * * la fila, por lo que esta solución es por lo general terriblemente inútil en 'tablas InnoDB' (o cualquier otro motor transaccional), ya que se ahoga con la mayoría de cualquier' restricción externa KEY' – Naltharial
Funciona bien con MySQL. Habiendo dicho eso, no tengo ninguna clave foránea en esa mesa. – algarecu
Como ninguna de estas soluciones parecen aún elegante. Una forma de fuerza bruta es consultar para ver si existe la fila. Si elimina la fila y luego inserte de lo contrario simplemente inserte. Obviamente, se trata de una sobrecarga, pero no depende de modificar el sql en bruto y funciona en cosas no orm.
Ya sabes, puedes ir al DBA-Hell por esto. – strangeqargo
acabo de utilizar SQL claro como:
insert_stmt = "REPLACE INTO tablename (column1, column2) VALUES (:column_1_bind, :columnn_2_bind) "
session.execute(insert_stmt, data)
Es depende de usted.Si desea reemplazar luego pasar OR REPLACE
en prefijos
def bulk_insert(self,objects,table):
#table: Your table class and objects are list of dictionary [{col1:val1, col2:vale}]
for counter,row in enumerate(objects):
inserter = table.__table__.insert(prefixes=['OR IGNORE'], values=row)
try:
self.db.execute(inserter)
except Exception as E:
print E
if counter % 100 == 0:
self.db.commit()
self.db.commit()
Aquí cometer intervalo se puede cambiar para acelerar o bajar la velocidad
Basado en phsource's answer, y para el caso de uso específico de usar MySQL y anulando por completo los datos para la misma clave sin realizar una declaración DELETE
, se puede utilizar la siguiente expresión @compiles
inserto decorado:
from sqlalchemy.ext.compiler import compiles
from sqlalchemy.sql.expression import Insert
@compiles(Insert)
def append_string(insert, compiler, **kw):
s = compiler.visit_insert(insert, **kw)
if insert.kwargs.get('on_duplicate_key_update'):
fields = s[s.find("(") + 1:s.find(")")].replace(" ", "").split(",")
generated_directive = ["{0}=VALUES({0})".format(field) for field in fields]
return s + " ON DUPLICATE KEY UPDATE " + ",".join(generated_directive)
return s
debería mencionar que desde la liberación de la versión 1.2, la SQLAlchemy 'núcleo' tiene una solución a lo anterior con que se construye y se puede ver bajo here (fragmento copiado abajo):
from sqlalchemy.dialects.mysql import insert
insert_stmt = insert(my_table).values(
id='some_existing_id',
data='inserted value')
on_duplicate_key_stmt = insert_stmt.on_duplicate_key_update(
data=insert_stmt.inserted.data,
status='U'
)
conn.execute(on_duplicate_key_stmt)
- 1. ACTUALIZACIÓN DE LLAVE DUPLICADA con WHERE condición
- 2. MySQL 'ACTUALIZACIÓN EN LLAVE DUPLICADA' sin una columna única?
- 3. Mysql Error de entrada duplicada en ON ACTUALIZACIÓN DE LLAVE DUPLICADA
- 4. MySQL - EN llave duplicada INSERT
- 5. INSERTAR ... ¿ACTUALIZAR LLAVE DUPLICADA con DÓNDE?
- 6. Disparador en INSERTAR EN LLAVE DUPLICADA
- 7. ¿Hay MySQL ... INSERTAR ... EN SELECCIÓN DE LLAVE DUPLICADA?
- 8. ¿Cuáles son las diferencias prácticas entre 'REEMPLAZAR' e 'INSERTAR ... EN ACTUALIZACIÓN DE LLAVE DUPLICADA' en MySQL?
- 9. ¿Por qué se ven afectadas 2 filas en mi `INSERTAR ... EN ACTUALIZACIÓN DE LLAVE DUPLICADA '?
- 10. condicional en la actualización de clave duplicada
- 11. sencilla actualización en sqlalchemy
- 12. Actualización de clave duplicada - Varias columnas
- 13. MySQL en actualización de clave duplicada
- 14. Sqlalchemy: actualización secundaria de relaciones
- 15. Django - save() actualización en clave duplicada
- 16. Actualización de aplicaciones web Pyramid/SQLAlchemy
- 17. SQLAlchemy - seleccionar para el ejemplo de actualización
- 18. Inserción de PDO en la actualización de clave duplicada
- 19. MongoDB: insertar en la actualización de clave duplicada
- 20. inserción condicional de mysql en la actualización duplicada - registros múltiples
- 21. actualización SQLAlchemy si existe clave única
- 22. Actualización eficiente de la base de datos usando SQLAlchemy ORM
- 23. ¿Cómo realizo eficientemente una inserción o actualización masiva con SQLAlchemy?
- 24. GetHashCode (llave) y int.MaxValue
- 25. incapaz de dejar la llave
- 26. OTHER_CODE_SIGN_FLAGS indicador de llave ¿ignorado?
- 27. Xcode - escena duplicada Storyboard
- 28. MySQL - Tabla duplicada
- 29. MySQL Insertar de clave duplicada
- 30. Cómo adquirir un candado con una llave
Tenga en cuenta que la El código 'append_string' no es funcional en postgres (con su nueva función' ON CONFLICT [IGNORE | UPDATE] 'en 9.5, ya que ORM agrega automáticamente un' RETURNING {primary key} 'a las inserciones, y eso da como resultado SQL no válido. –
¿Cómo puedo hacer que esto funcione con Postgres 9.5? – puredevotion
¿Qué está haciendo la parte 'foo = foo' aquí y con qué reemplazaría' foo' en mi propia tabla? – nhinkle