Skip to content

Unify INSERT ... ON CONFLICT / UPSERT / MERGE functionality in single implementation #8321

Open

Description

@CaselIT

The current support for insert on conflict requires the use of an insert() function from the specific dialect package.
This is inconvenient since it's make it hard to port the code from one dialect to another.

Since the functionality is similar we could have a single implementation and dialect that do not support something could raise not implemented like it happens in other parts of sqlalchemy

Activity

  1. added
    use casenot really a feature or a bug; can be support for new DB features or user use cases not anticipated
    dialectsgeneral dialect tag. useful for unsupported dbs or deprecations. not needed for specific dbs.
    on Aug 1, 2022
  2. added this to the 2.x.x milestone on Aug 1, 2022
  3. changed the title [-]Unify INSERT ... ON CONFLICT functionality in single implementation[/-] [+]Unify INSERT ... ON CONFLICT / UPSERT / MERGE functionality in single implementation[/+] on May 23, 2023
  4. changed the title [-]Unify INSERT ... ON CONFLICT / UPSERT / MERGE functionality in single implementation[/-] [+]Unify INSERT ... ON CONFLICT / UPSERT functionality in single implementation[/+] on Sep 27, 2023
  5. modified the milestones: 2.x.x, 2.1 on Sep 27, 2023
  6. changed the title [-]Unify INSERT ... ON CONFLICT / UPSERT functionality in single implementation[/-] [+]Unify INSERT ... ON CONFLICT / UPSERT / MERGE functionality in single implementation[/+] on Sep 27, 2023
  7. modified the milestones: 2.1, 2.x.x on Oct 28, 2023
  8. zzzeek commented on Oct 28, 2023

    @zzzeek
    Member

    out of scope for 2.1

  9. fdcastel commented on Jan 8, 2024

    @fdcastel
    Contributor

    I'm also interested in this one. This is a very common scenario, and it's hard to imagine any RDBMS in today's times that doesn't offer anything in this direction.

    For reference: When designing the new API, please take a look into the Firebird options to solve this:

  10. pythonweb2 commented on Sep 8, 2025

    @pythonweb2

    I ran into this today. I'm trying to run my tests in a SQLite database, because it can run in memory, and it is easy to setup/tear down the database. I have a statement like this where I insert where a unique constraint is present, and would like it to work for both postgresql and sqlite.

    Amusingly, it seems like the syntax may be the same for both of them, but what is the recommended approach to writing statements that can be used in multiple dialects? Or perhaps the conditional flow for doing such. I searched through the docs but didn't see anything like that.

  11. zzzeek commented on Sep 8, 2025

    @zzzeek
    Member

    if you're targeting postgresql and sqlite, you can probably use the postgresql insert() object and just run it with the sqlite engine and it might just work since the two are implemented as similarly as possible. you of course would have to use the subset of syntaxes that works on both backends.

    or you could do a compiles recipe: https://docs.sqlalchemy.org/en/20/core/compiler.html that takes in the PG version of the statement and rewrites it as a SQLite one, if there's some incompatibility to be resolved.

  12. CaselIT commented on Oct 16, 2026

    @CaselIT
    MemberAuthor

    Just though of this option.

    given that 2.1 added https://docs.sqlalchemy.org/en/21/core/compiler.html#sqlalchemy.sql.SyntaxExtension applied to a statement using https://docs.sqlalchemy.org/en/21/core/selectable.html#sqlalchemy.sql.expression.Select.ext and similar, and that the current insert logic are also already built using this extension pattern, I wonder if a pre-database logic could maybe bolt on this api, ideally directly in the 2.1 series as backward compatible, so that an insert could include different db-scoped extension clauses for the on conflict logic.
    something like sqlachemy.insert(...).ext(the_pg_thing, 'pg').ext(the_sqlite_thing, 'sqlite') etc?
    This would still not be unified, but it's better than nothing I guess.

    @zzzeek shame we didn't think about using ext for this from the start.

  13. zzzeek commented on Oct 16, 2026

    @zzzeek
    Member

    this is an example of an issue where I've always felt the thinking, edge case catching, and understanding of exactly what would be most useful, was both not worth it for me and also I didnt have my own experiences needing "cross-database-UPSERT" to really understand what would be useful.

    now that we have robots it might be worth starting off by doing something in sqlalchemy.ext here.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    dialectsgeneral dialect tag. useful for unsupported dbs or deprecations. not needed for specific dbs.sqlupsertsuse casenot really a feature or a bug; can be support for new DB features or user use cases not anticipated

    Type

    No type

    Projects

    No projects

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions