I'm using SQLAlchemy 1.3.4 and PostgreSQL 11.3.
I have the following (simplified) table definition:
class MyModel(Base):
__tablename__ = 'mymodel'
id = Column(Integer, primary_key=True)
col1 = Column(Unicode, nullable=False)
col2 = Column(Unicode, nullable=False)
col3 = Column(Unicode, nullable=False)
col4 = Column(Boolean)
created_at = Column(DateTime(timezone=True), nullable=False)
updated_at = Column(DateTime(timezone=True), nullable=False)
__table_args__ = (
Index('uq_mymodel_col1_col2_col3_col4',
col1, col2, col3, col4,
unique=True, postgresql_where=col4.isnot(None)),
Index('uq_mymodel_col1_col2_col3',
col1, col2, col3,
unique=True, postgresql_where=col4.is_(None)),
)
(I had to create 2 unique index rather than a UniqueConstraint because a UniqueConstraint would allow multiple rows with the same (col1, col2, col3) is col4 is null, which I do not want)
I'm trying to do the following query:
INSERT INTO mymodel (col1, col2, col3, col4, created_at, updated_at)
VALUES (%(col1)s, %(col2)s, %(col3)s, %(col4)s, %(created_at)s, %(updated_at)s)
ON CONFLICT DO UPDATE SET updated_at = %(param_1)s
RETURNING mymodel.id
I can't figure out how to properly use SQLAlchemy's on_conflict_do_update() though. :-/
Here is what I tried:
values = {…}
stmt = insert(MyModel.__table__).values(**values)
stmt = stmt.returning(MyModel.__table__.c.id)
stmt = stmt.on_conflict_do_update(set_={'updated_at': values['updated_at']})
result = dbsession.connection().execute(stmt)
However SQLAlchemy complains: Either constraint or index_elements, but not both, must be specified unless DO NOTHING
I find it very unclear how to use constraint or index_elements.
I tried a few things, to no avail. For example:
values = {…}
stmt = insert(MyModel.__table__).values(**values)
stmt = stmt.returning(MyModel.__table__.c.id)
stmt = stmt.on_conflict_do_update(constraint='uq_mymodel_col1_col2_col3_col4'
set_={'updated_at': values['updated_at']})
result = dbsession.connection().execute(stmt)
But then this doesn't work either: constraint "uq_mymodel_col1_col2_col3_col4" for table "mymodel" does not exist. But it does exist. (I even copy-pasted from pgsql to make sure I hadn't made a typo)
In any case, I have two unique constraints which can raise a conflict, but on_conflict_do_update() seems to only take one. So I also tried specifying both like this:
values = {…}
stmt = insert(MyModel.__table__).values(**values)
stmt = stmt.returning(MyModel.__table__.c.id)
stmt = stmt.on_conflict_do_update(constraint='uq_mymodel_col1_col2_col3_col4'
set_={'updated_at': values['updated_at']})
stmt = stmt.on_conflict_do_update(constraint='uq_mymodel_col1_col2_col3'
set_={'updated_at': values['updated_at']})
result = dbsession.connection().execute(stmt)
But I get the same error, that the uq_mymodel_col1_col2_col3_col4 does not exist.
At this point I just can't figure out how to do the above query, and would really appreciate some help.