SQLAlchemy provides ``ON DUPLICATE KEY UPDATE`` support via the MySQL-specific
:func:`.mysql.insert()` function, which provides
-the generative method :meth:`~.mysql.Insert.on_duplicate_key_update`::
+the generative method :meth:`~.mysql.Insert.on_duplicate_key_update`:
- from sqlalchemy.dialects.mysql import insert
+.. sourcecode:: pycon+sql
- insert_stmt = insert(my_table).values(
- id='some_existing_id',
- data='inserted value')
+ >>> from sqlalchemy.dialects.mysql import insert
- on_duplicate_key_stmt = insert_stmt.on_duplicate_key_update(
- data=insert_stmt.inserted.data,
- status='U'
- )
+ >>> 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'
+ ... )
+ >>> print(on_duplicate_key_stmt)
+ {opensql}INSERT INTO my_table (id, data) VALUES (%s, %s)
+ ON DUPLICATE KEY UPDATE data = VALUES(data), status = %s
- conn.execute(on_duplicate_key_stmt)
Unlike PostgreSQL's "ON CONFLICT" phrase, the "ON DUPLICATE KEY UPDATE"
phrase will always match on any primary key or unique key, and will always
given column key values (usually the name of the column, unless it
specifies :paramref:`_schema.Column.key`
) as keys and literal or SQL expressions
-as values::
+as values:
- on_duplicate_key_stmt = insert_stmt.on_duplicate_key_update(
- data="some data",
- updated_at=func.current_timestamp(),
- )
+.. sourcecode:: pycon+sql
+
+ >>> insert_stmt = insert(my_table).values(
+ ... id='some_existing_id',
+ ... data='inserted value')
+
+ >>> on_duplicate_key_stmt = insert_stmt.on_duplicate_key_update(
+ ... data="some data",
+ ... updated_at=func.current_timestamp(),
+ ... )
+
+ >>> print(on_duplicate_key_stmt)
+ {opensql}INSERT INTO my_table (id, data) VALUES (%s, %s)
+ ON DUPLICATE KEY UPDATE data = %s, updated_at = CURRENT_TIMESTAMP
In a manner similar to that of :meth:`.UpdateBase.values`, other parameter
-forms are accepted, including a single dictionary::
+forms are accepted, including a single dictionary:
- on_duplicate_key_stmt = insert_stmt.on_duplicate_key_update(
- {"data": "some data", "updated_at": func.current_timestamp()},
- )
+.. sourcecode:: pycon+sql
+
+ >>> on_duplicate_key_stmt = insert_stmt.on_duplicate_key_update(
+ ... {"data": "some data", "updated_at": func.current_timestamp()},
+ ... )
as well as a list of 2-tuples, which will automatically provide
a parameter-ordered UPDATE statement in a manner similar to that described
at :ref:`updates_order_parameters`. Unlike the :class:`_expression.Update`
object,
no special flag is needed to specify the intent since the argument form is
-this context is unambiguous::
+this context is unambiguous:
- on_duplicate_key_stmt = insert_stmt.on_duplicate_key_update(
- [
- ("data", "some data"),
- ("updated_at", func.current_timestamp()),
- ],
- )
+.. sourcecode:: pycon+sql
+
+ >>> on_duplicate_key_stmt = insert_stmt.on_duplicate_key_update(
+ ... [
+ ... ("data", "some data"),
+ ... ("updated_at", func.current_timestamp()),
+ ... ]
+ ... )
+
+ >>> print(on_duplicate_key_stmt)
+ {opensql}INSERT INTO my_table (id, data) VALUES (%s, %s)
+ ON DUPLICATE KEY UPDATE data = %s, updated_at = CURRENT_TIMESTAMP
.. versionchanged:: 1.3 support for parameter-ordered UPDATE clause within
MySQL ON DUPLICATE KEY UPDATE
:attr:`~.mysql.Insert.inserted` is available as an attribute on
the :class:`.mysql.Insert` object; this object is a
:class:`_expression.ColumnCollection` which contains all columns of the target
-table::
+table:
- from sqlalchemy.dialects.mysql import insert
+.. sourcecode:: pycon+sql
- stmt = insert(my_table).values(
- id='some_id',
- data='inserted value',
- author='jlh')
- do_update_stmt = stmt.on_duplicate_key_update(
- data="updated value",
- author=stmt.inserted.author
- )
- conn.execute(do_update_stmt)
+ >>> stmt = insert(my_table).values(
+ ... id='some_id',
+ ... data='inserted value',
+ ... author='jlh')
+
+ >>> do_update_stmt = stmt.on_duplicate_key_update(
+ ... data="updated value",
+ ... author=stmt.inserted.author
+ ... )
+
+ >>> print(do_update_stmt)
+ {opensql}INSERT INTO my_table (id, data, author) VALUES (%s, %s, %s)
+ ON DUPLICATE KEY UPDATE data = %s, author = VALUES(author)
When rendered, the "inserted" namespace will produce the expression
``VALUES(<columnname>)``.
SQLAlchemy provides ``ON CONFLICT`` support via the PostgreSQL-specific
:func:`_postgresql.insert()` function, which provides
the generative methods :meth:`~.postgresql.Insert.on_conflict_do_update`
-and :meth:`~.postgresql.Insert.on_conflict_do_nothing`::
-
- from sqlalchemy.dialects.postgresql import insert
-
- insert_stmt = insert(my_table).values(
- id='some_existing_id',
- data='inserted value')
-
- do_nothing_stmt = insert_stmt.on_conflict_do_nothing(
- index_elements=['id']
- )
-
- conn.execute(do_nothing_stmt)
-
- do_update_stmt = insert_stmt.on_conflict_do_update(
- constraint='pk_my_table',
- set_=dict(data='updated value')
- )
-
- conn.execute(do_update_stmt)
+and :meth:`~.postgresql.Insert.on_conflict_do_nothing`:
+
+.. sourcecode:: pycon+sql
+
+ >>> from sqlalchemy.dialects.postgresql import insert
+ >>> insert_stmt = insert(my_table).values(
+ ... id='some_existing_id',
+ ... data='inserted value')
+ >>> do_nothing_stmt = insert_stmt.on_conflict_do_nothing(
+ ... index_elements=['id']
+ ... )
+ >>> print(do_nothing_stmt)
+ {opensql}INSERT INTO my_table (id, data) VALUES (%(id)s, %(data)s)
+ ON CONFLICT (id) DO NOTHING
+ {stop}
+
+ >>> do_update_stmt = insert_stmt.on_conflict_do_update(
+ ... constraint='pk_my_table',
+ ... set_=dict(data='updated value')
+ ... )
+ >>> print(do_update_stmt)
+ {opensql}INSERT INTO my_table (id, data) VALUES (%(id)s, %(data)s)
+ ON CONFLICT ON CONSTRAINT pk_my_table DO UPDATE SET data = %(param_1)s
Both methods supply the "target" of the conflict using either the
named constraint or by column inference:
* The :paramref:`.Insert.on_conflict_do_update.index_elements` argument
specifies a sequence containing string column names, :class:`_schema.Column`
objects, and/or SQL expression elements, which would identify a unique
- index::
-
- do_update_stmt = insert_stmt.on_conflict_do_update(
- index_elements=['id'],
- set_=dict(data='updated value')
- )
-
- do_update_stmt = insert_stmt.on_conflict_do_update(
- index_elements=[my_table.c.id],
- set_=dict(data='updated value')
- )
+ index:
+
+ .. sourcecode:: pycon+sql
+
+ >>> do_update_stmt = insert_stmt.on_conflict_do_update(
+ ... index_elements=['id'],
+ ... set_=dict(data='updated value')
+ ... )
+ >>> print(do_update_stmt)
+ {opensql}INSERT INTO my_table (id, data) VALUES (%(id)s, %(data)s)
+ ON CONFLICT (id) DO UPDATE SET data = %(param_1)s
+ {stop}
+
+ >>> do_update_stmt = insert_stmt.on_conflict_do_update(
+ ... index_elements=[my_table.c.id],
+ ... set_=dict(data='updated value')
+ ... )
+ >>> print(do_update_stmt)
+ {opensql}INSERT INTO my_table (id, data) VALUES (%(id)s, %(data)s)
+ ON CONFLICT (id) DO UPDATE SET data = %(param_1)s
* When using :paramref:`.Insert.on_conflict_do_update.index_elements` to
infer an index, a partial index can be inferred by also specifying the
- use the :paramref:`.Insert.on_conflict_do_update.index_where` parameter::
+ use the :paramref:`.Insert.on_conflict_do_update.index_where` parameter:
- from sqlalchemy.dialects.postgresql import insert
+ .. sourcecode:: pycon+sql
- stmt = insert(my_table).values(user_email='a@b.com', data='inserted data')
- stmt = stmt.on_conflict_do_update(
- index_elements=[my_table.c.user_email],
- index_where=my_table.c.user_email.like('%@gmail.com'),
- set_=dict(data=stmt.excluded.data)
- )
- conn.execute(stmt)
+ >>> stmt = insert(my_table).values(user_email='a@b.com', data='inserted data')
+ >>> stmt = stmt.on_conflict_do_update(
+ ... index_elements=[my_table.c.user_email],
+ ... index_where=my_table.c.user_email.like('%@gmail.com'),
+ ... set_=dict(data=stmt.excluded.data)
+ ... )
+ >>> print(stmt)
+ {opensql}INSERT INTO my_table (data, user_email)
+ VALUES (%(data)s, %(user_email)s) ON CONFLICT (user_email)
+ WHERE user_email LIKE %(user_email_1)s DO UPDATE SET data = excluded.data
* The :paramref:`.Insert.on_conflict_do_update.constraint` argument is
used to specify an index directly rather than inferring it. This can be
- the name of a UNIQUE constraint, a PRIMARY KEY constraint, or an INDEX::
-
- do_update_stmt = insert_stmt.on_conflict_do_update(
- constraint='my_table_idx_1',
- set_=dict(data='updated value')
- )
-
- do_update_stmt = insert_stmt.on_conflict_do_update(
- constraint='my_table_pk',
- set_=dict(data='updated value')
- )
+ the name of a UNIQUE constraint, a PRIMARY KEY constraint, or an INDEX:
+
+ .. sourcecode:: pycon+sql
+
+ >>> do_update_stmt = insert_stmt.on_conflict_do_update(
+ ... constraint='my_table_idx_1',
+ ... set_=dict(data='updated value')
+ ... )
+ >>> print(do_update_stmt)
+ {opensql}INSERT INTO my_table (id, data) VALUES (%(id)s, %(data)s)
+ ON CONFLICT ON CONSTRAINT my_table_idx_1 DO UPDATE SET data = %(param_1)s
+ {stop}
+
+ >>> do_update_stmt = insert_stmt.on_conflict_do_update(
+ ... constraint='my_table_pk',
+ ... set_=dict(data='updated value')
+ ... )
+ >>> print(do_update_stmt)
+ {opensql}INSERT INTO my_table (id, data) VALUES (%(id)s, %(data)s)
+ ON CONFLICT ON CONSTRAINT my_table_pk DO UPDATE SET data = %(param_1)s
+ {stop}
* The :paramref:`.Insert.on_conflict_do_update.constraint` argument may
also refer to a SQLAlchemy construct representing a constraint,
construct. This use is especially convenient
to refer to the named or unnamed primary key of a :class:`_schema.Table`
using the
- :attr:`_schema.Table.primary_key` attribute::
+ :attr:`_schema.Table.primary_key` attribute:
- do_update_stmt = insert_stmt.on_conflict_do_update(
- constraint=my_table.primary_key,
- set_=dict(data='updated value')
- )
+ .. sourcecode:: pycon+sql
+
+ >>> do_update_stmt = insert_stmt.on_conflict_do_update(
+ ... constraint=my_table.primary_key,
+ ... set_=dict(data='updated value')
+ ... )
+ >>> print(do_update_stmt)
+ {opensql}INSERT INTO my_table (id, data) VALUES (%(id)s, %(data)s)
+ ON CONFLICT (id) DO UPDATE SET data = %(param_1)s
``ON CONFLICT...DO UPDATE`` is used to perform an update of the already
existing row, using any combination of new values as well as values
from the proposed insertion. These values are specified using the
:paramref:`.Insert.on_conflict_do_update.set_` parameter. This
parameter accepts a dictionary which consists of direct values
-for UPDATE::
+for UPDATE:
- from sqlalchemy.dialects.postgresql import insert
+.. sourcecode:: pycon+sql
- stmt = insert(my_table).values(id='some_id', data='inserted value')
- do_update_stmt = stmt.on_conflict_do_update(
- index_elements=['id'],
- set_=dict(data='updated value')
- )
- conn.execute(do_update_stmt)
+ >>> stmt = insert(my_table).values(id='some_id', data='inserted value')
+ >>> do_update_stmt = stmt.on_conflict_do_update(
+ ... index_elements=['id'],
+ ... set_=dict(data='updated value')
+ ... )
+ >>> print(do_update_stmt)
+ {opensql}INSERT INTO my_table (id, data) VALUES (%(id)s, %(data)s)
+ ON CONFLICT (id) DO UPDATE SET data = %(param_1)s
.. warning::
the :class:`_postgresql.Insert` object; this object is a
:class:`_expression.ColumnCollection`
which alias contains all columns of the target
-table::
-
- from sqlalchemy.dialects.postgresql import insert
-
- stmt = insert(my_table).values(
- id='some_id',
- data='inserted value',
- author='jlh')
- do_update_stmt = stmt.on_conflict_do_update(
- index_elements=['id'],
- set_=dict(data='updated value', author=stmt.excluded.author)
- )
- conn.execute(do_update_stmt)
+table:
+
+.. sourcecode:: pycon+sql
+
+ >>> stmt = insert(my_table).values(
+ ... id='some_id',
+ ... data='inserted value',
+ ... author='jlh'
+ ... )
+ >>> do_update_stmt = stmt.on_conflict_do_update(
+ ... index_elements=['id'],
+ ... set_=dict(data='updated value', author=stmt.excluded.author)
+ ... )
+ >>> print(do_update_stmt)
+ {opensql}INSERT INTO my_table (id, data, author)
+ VALUES (%(id)s, %(data)s, %(author)s)
+ ON CONFLICT (id) DO UPDATE SET data = %(param_1)s, author = excluded.author
The :meth:`_expression.Insert.on_conflict_do_update` method also accepts
a WHERE clause using the :paramref:`.Insert.on_conflict_do_update.where`
-parameter, which will limit those rows which receive an UPDATE::
-
- from sqlalchemy.dialects.postgresql import insert
-
- stmt = insert(my_table).values(
- id='some_id',
- data='inserted value',
- author='jlh')
- on_update_stmt = stmt.on_conflict_do_update(
- index_elements=['id'],
- set_=dict(data='updated value', author=stmt.excluded.author)
- where=(my_table.c.status == 2)
- )
- conn.execute(on_update_stmt)
+parameter, which will limit those rows which receive an UPDATE:
+
+.. sourcecode:: pycon+sql
+
+ >>> stmt = insert(my_table).values(
+ ... id='some_id',
+ ... data='inserted value',
+ ... author='jlh'
+ ... )
+ >>> on_update_stmt = stmt.on_conflict_do_update(
+ ... index_elements=['id'],
+ ... set_=dict(data='updated value', author=stmt.excluded.author),
+ ... where=(my_table.c.status == 2)
+ ... )
+ >>> print(on_update_stmt)
+ {opensql}INSERT INTO my_table (id, data, author)
+ VALUES (%(id)s, %(data)s, %(author)s)
+ ON CONFLICT (id) DO UPDATE SET data = %(param_1)s, author = excluded.author
+ WHERE my_table.status = %(status_1)s
``ON CONFLICT`` may also be used to skip inserting a row entirely
if any conflict with a unique or exclusion constraint occurs; below
this is illustrated using the
-:meth:`~.postgresql.Insert.on_conflict_do_nothing` method::
+:meth:`~.postgresql.Insert.on_conflict_do_nothing` method:
- from sqlalchemy.dialects.postgresql import insert
+.. sourcecode:: pycon+sql
- stmt = insert(my_table).values(id='some_id', data='inserted value')
- stmt = stmt.on_conflict_do_nothing(index_elements=['id'])
- conn.execute(stmt)
+ >>> stmt = insert(my_table).values(id='some_id', data='inserted value')
+ >>> stmt = stmt.on_conflict_do_nothing(index_elements=['id'])
+ >>> print(stmt)
+ {opensql}INSERT INTO my_table (id, data) VALUES (%(id)s, %(data)s)
+ ON CONFLICT (id) DO NOTHING
If ``DO NOTHING`` is used without specifying any columns or constraint,
it has the effect of skipping the INSERT for any unique or exclusion
-constraint violation which occurs::
+constraint violation which occurs:
- from sqlalchemy.dialects.postgresql import insert
+.. sourcecode:: pycon+sql
- stmt = insert(my_table).values(id='some_id', data='inserted value')
- stmt = stmt.on_conflict_do_nothing()
- conn.execute(stmt)
+ >>> stmt = insert(my_table).values(id='some_id', data='inserted value')
+ >>> stmt = stmt.on_conflict_do_nothing()
+ >>> print(stmt)
+ {opensql}INSERT INTO my_table (id, data) VALUES (%(id)s, %(data)s)
+ ON CONFLICT DO NOTHING
.. versionadded:: 1.1 Added support for PostgreSQL ON CONFLICT clauses