Skip to content

Use UPSERT (aka INSERT ... ON CONFLICT SET) in .upsert() and .upsert_all() when available #652

@simonw

Description

@simonw

SQLite added UPSERT support (in the shape of INSERT ... ON CONFLICT SET) in version 3.24.0, released 2018-06-04.

https://sqlite.org/lang_upsert.html

sqlite-utils has .upsert() and .upsert_all() which were updated to have the correct semantics in 2019 in:

As noted in this comment:

If I do implement the correct definition of .upsert() I think I'll use this pattern, since it works in versions of SQLite prior to 3.24:

INSERT OR IGNORE INTO book(id) VALUES(1001);
UPDATE book SET name = 'Programming' WHERE id = 1001;

That was more than five years ago. I think UPSERT is probably a whole lot more available now than it was then.

Meanwhile... my work on SQLite Chronicle (tracking version numbers for SQLite rows automatically using triggers, to help support syncing, subscribing to tables and implementing logic that only looks at rows that are new/updated since the last check) has been stymied by the fact that INSERT OR REPLACE can't be correctly detected by triggers - it's indistinguishable from a delete followed by an insert, so I can't reliably maintain the same version number for a row if an INSERT OR REPLACE does a no-op:

As such, I'd like to start using real upserts instead in a bunch of places in the Datasette ecosystem.

So... I think it's time sqlite-utils learned to use upsert. I'm not sure how many pre-3.24.0 installs are still around, so it could implement feature detection and switch to the older mechanism if upsert isn't supported.

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Projects

    No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions