13

I'm using SQLAlchemy Core with a MySQL database but am having a hard time finding a solution for INSERT IGNORE / DUPLICATE KEY UPDATE. I hate to write a one-off query manually in the code if there's a way to handle this. Most solutions or discussions I've found center around the ORM, but not the core. And even some of those are dead links. Is it even possible?

TravisVOX
  • 20,342
  • 13
  • 37
  • 41

4 Answers4

18

I know it is a bit late.. but if someone is still looking for solutions.

FOR: ON DUPLICATE KEY UPDATE

ins = insert(/* table_name*/ ).values(/*your values(with PK)*/)
do_update_stmt = ins.on_duplicate_key_update(/*your values(with out PK)*/)
connection.execute(do_update_stmt)

On duplicate key update docs

The ON DUPLICATE KEY UPDATE clause of INSERT supported by MySQL is now supported using a MySQL-specific version of the Insert object

This wont be avaliable with sqlalchemy.insert().

FOR: INSERT IGNORE

This is a bit hacky but works just fine.

 ins_address_stmt = insert(/* table_name*/ ).values(/*your values*/). \
            prefix_with('IGNORE')

Insert prefix_with

MySQL will suppress the error for duplicate primary key and gives a warning.

TrilceAC
  • 301
  • 3
  • 10
shaktimaan
  • 1,769
  • 13
  • 14
  • 1
    Do you know what data does (values) receive? I’ve tried with a list of class instances (just like I would with add_all() but it doesn’t work... – lowercase00 Apr 09 '19 at 03:29
  • 1
    Sorry for the late reply... `values()` takes in values to be inserted as arguments. Argument name should match tables columns. For e.g. `insert(customers).values(name=name, phone=phone,is_approved=is_approved)` And Table's structure is `Table ('customers', metadata, Column('name'), Column('phone'), Column('is_approved')` – shaktimaan Apr 13 '19 at 07:51
  • Thanks, I tried inserting the class’ instances but it ends up trying to insert the SQLAlchemy object itself, instead of the values. I chose to partially commit my code to the DB in order to avoid the eventual integrity error. I might try to drill down on the object and insert the values. – lowercase00 Apr 13 '19 at 09:11
10

shaktimaan's answer works great for MySQL INSERT IGNORE. If you found this page looking for SQLite INSERT IGNORE, remember to do INSERT OR IGNORE

https://www.sqlite.org/lang_insert.html

stmt = insert(/* table_name*/ ).values(/*your values*/).prefix_with('OR IGNORE')
Bryan
  • 184
  • 1
  • 4
1

Another method is:

stmt = YourModel.__table__.insert().prefix_with(" ignore").values(data)
session.execute(stmt)
buxizhizhoum
  • 1,719
  • 1
  • 23
  • 32
0

SQL Mode


print '--------- test upsert --------------'
for r in rows:
    r['value'] = r['id'] + 1

sql = '''
    INSERT INTO test (id, value)
    VALUES (:id, :value)
    ON DUPLICATE KEY UPDATE value = VALUES(value)
'''
start = time.time()
engine.execute(text(sql), rows)

codelover
  • 44
  • 3