Existe-t-il un moyen élégant de faire un INSERT ... ON DUPLICATE KEY UPDATE
dans SQLAlchemy ? Je veux dire quelque chose avec une syntaxe similaire à inserter.insert().execute(list_of_dictionaries)
?
Réponses
Trop de publicités?Je dois mentionner que depuis la sortie de v1.2, « noyau » du SQLAlchemy a une solution à ce qui précède avec qui est construit et peut être vu sous ici (extrait copié ci - dessous):
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)
Sur la base de la réponse de phsource , et pour le cas d'utilisation spécifique d'utilisation de MySQL et de remplacement complet des données pour la même clé sans exécuter une DELETE
, on peut utiliser l'insert décoré @compiles
expression:
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
Cela dépend de vous. Si vous voulez remplacer alors passez OR REPLACE
dans les préfixes
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()
Ici, l'intervalle de validation peut être modifié pour accélérer ou ralentir
J'ai une solution plus 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)