diff options
author | Robin Thomas <robin.thomas@livestream.com> | 2016-04-14 11:07:49 -0400 |
---|---|---|
committer | Robin Thomas <robin.thomas@livestream.com> | 2016-04-14 11:07:49 -0400 |
commit | 3a7e94c4d5091bebb5d67246b9888d97ea85e691 (patch) | |
tree | f5ab33f4bf1eb52bb521289659b08ffff5d99ef3 | |
parent | a7bc406390ebcce9cb10d2b39bdfa55cdc894b49 (diff) | |
download | sqlalchemy-3a7e94c4d5091bebb5d67246b9888d97ea85e691.tar.gz |
finished docs (sans formatting and linking checks) for ON CONFLICT,
including explanation of using constraint object as conflict targets.
-rw-r--r-- | lib/sqlalchemy/dialects/postgresql/base.py | 41 |
1 files changed, 37 insertions, 4 deletions
diff --git a/lib/sqlalchemy/dialects/postgresql/base.py b/lib/sqlalchemy/dialects/postgresql/base.py index 6c50c19c3..4ef6a3087 100644 --- a/lib/sqlalchemy/dialects/postgresql/base.py +++ b/lib/sqlalchemy/dialects/postgresql/base.py @@ -247,6 +247,8 @@ use the :meth:`._UpdateBase.returning` method on a per-statement basis:: where(table.c.name=='foo') print result.fetchall() +.. _postgresql_insert_on_conflict: + INSERT...ON CONFLICT (Upsert) ------------------------- @@ -273,17 +275,48 @@ of the row proposed for insert. Use the value `'update'` for the keyword argumen and the SQL compiler will produce an ``ON CONFLICT`` clause that performs ``DO UPDATE SET...`` for every column value in the ``VALUES`` clause that is not a primary key column for the target table. The produced SQL will use the primary key -columns as the "conflict target" in the ``ON CONFLICT`` clause. +columns as the "conflict target" in the ``ON CONFLICT`` clause. This usage +requires that the targeted table have at least one column participating +in a `PrimaryKeyConstraint`. `ON CONFLICT` is also commonly used to skip inserting a row entirely -if a conflict occurs. To do this, use the value 'nothing' for the keyword argument: +if any conflict occurs. To do this, use the value 'nothing' for the keyword argument: table.insert(postgresql_on_conflict='nothing').\\ values(key_column='existing_value', other_column='foo') -Other, more sophisticated forms of ``ON CONFLICT`` are possible, but they are +Less commonly, you may need to specify which of several unique constraints on a table +should be used to determine if an insert conflict exists. In these cases, use +the :class:`.DoNothing` or :class:`.DoUpdate` object, and pass one of the following +to indicate the "conflict target" constraint: + +* a single Column object or string with the column's name +* a list or tuple of several Column objects or name strings +* a :class:`.PrimaryKeyConstraint`, :class:`.UniqueConstraint`, + or :class:`.postgresql.ExcludeConstraint` object representing + the unique constraint to target. + +If you use :class:`.DoUpdate`, you need to specify which columns on the existing row +to set with values from the row proposed for insert. Use the +:meth:`.DoUpdate.set_with_excluded` chaining method to do so, passing a variable +set of Column or Column name string arguments for the columns to set using +the special `excluded` alias representing the row proposed for insertion: + + from sqlalchemy.dialects.postgresql import DoUpdate, DoNothing + from sqlalchemy.schema import UniqueConstraint + + unique_constr = UniqueConstraint(table.c.username) + update_action = DoUpdate(unique_constr).set_with_excluded('key_column', 'other_column') + + table.insert(postgresql_on_conflict=update_action).\\ + .values(key_column='existing_value', other_column='foo') + +Other, more sophisticated forms of ``ON CONFLICT`` are possible, especially +in what can be put in `SET ...` clauses, but they are not yet supported or documented by the dialect. Use text-based statements -for more advanced ``ON CONFLICT`` clauses. For more information, see the +for more advanced ``ON CONFLICT`` clauses. + +For more information on the PostgreSQL feature, see the ``ON CONFLICT` section of the `INSERT` statement in the PostgreSQL docs <http://www.postgresql.org/docs/current/static/sql-insert.html#SQL-ON-CONFLICT>`_. |