Skip to content

Conversation

@JanJakes
Copy link
Member

@JanJakes JanJakes commented Jan 6, 2026

In MySQL, a compound PRIMARY KEY can have an AUTOINCREMENT column, when it is the first column in the key.

SQLite doesn't support this, but we can emulate it as follows:

  1. Keep only the first column as a PRIMARY KEY.
    Since this is the column that also has AUTOINCREMENT, it reasonable to assume that its values are unique.
  2. Create a UNIQUE key for all the PRIMARY KEY columns.
    This is to preserve the index of the compound key.

The actual fix is best viewed in the second commit.

@JanJakes JanJakes force-pushed the compound-pk-autoincrement branch 3 times, most recently from 80ab70f to 1f8ebce Compare January 6, 2026 16:22
@JanJakes JanJakes force-pushed the compound-pk-autoincrement branch from 1f8ebce to c6074c6 Compare January 6, 2026 16:25
@JanJakes JanJakes requested a review from a team January 6, 2026 16:39
Copy link
Member

@brandonpayton brandonpayton left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@JanJakes I think this will work for most cases, but with this scheme, there are queries for the test table that work with MySQL but not SQLite.

For the test table

CREATE TABLE t1 (id INT AUTO_INCREMENT, name VARCHAR(32), PRIMARY KEY(id, name))'

In MySQL, you can INSERT two different rows with the same id as long as name is different:

MariaDB [149697504]> CREATE TABLE t1 (id INT AUTO_INCREMENT, name VARCHAR(32), PRIMARY KEY(id, name));
Query OK, 0 rows affected (0.002 sec)

MariaDB [149697504]> INSERT INTO t1 (id, name) VALUES (4, 'four');
Query OK, 1 row affected (0.001 sec)

MariaDB [149697504]> INSERT INTO t1 (id, name) VALUES (4, 'another value');
Query OK, 1 row affected (0.001 sec)

MariaDB [149697504]> SELECT * FROM t1;
+----+---------------+
| id | name          |
+----+---------------+
|  4 | another value |
|  4 | four          |
+----+---------------+

But in the SQLite scheme, it does not work because id is constrained to be unique on its own:

sqlite> CREATE TABLE t2 (id INTEGER PRIMARY KEY AUTOINCREMENT, name VARCHAR(32));
sqlite> CREATE UNIQUE INDEX compound_primary ON t2 (id, name);
sqlite> INSERT INTO t2 (id, name) VALUES (4, 'four');
sqlite> INSERT INTO t2 (id, name) VALUES (4, 'another value');
Runtime error: UNIQUE constraint failed: t2.id (19)
sqlite> 

Is there another way we could approach this? What do you think?

@JanJakes
Copy link
Member Author

JanJakes commented Jan 8, 2026

@brandonpayton Thanks for the in-depth feedback!

In MySQL, you can INSERT two different rows with the same id as long as name is different:
But in the SQLite scheme, it does not work because id is constrained to be unique on its own:

Yeah, it's definitely a limitation of this simple approach, but I think it's probably fine to keep this limitation, at least until we encounter some real-life scenario where this causes issues.

My reasoning behind this is the following (also documented in a comment):

Keep only the first column as a PRIMARY KEY. Since this is the column that also has AUTOINCREMENT, it reasonable to assume that its values are unique.

In other words, having a primary key that is a combination of autoincrement and some other columns seems pretty unusual—normally one either wants a column to be automatically incremented or manually inserted.

Is there another way we could approach this? What do you think?

Originally, I was thinking along these lines (and didn't consider such an approach to be worth it):

  1. We can keep the compound PRIMARY KEY without AUTOINCREMENT.
  2. We can use a trigger to simulate AUTOINCREMENT.

So far so good, but here's the problem:

ALTER TABLE t AUTO_INCREMENT = 123;

Now, we'd need the trigger to actually maintain a modifiable sequence somewhere, and it gets all a bit too complicated. Unfortunately, AUTOINCREMENT in SQLite requires PRIMARY KEY, so there is no easy way around that. SQLite also doesn't have Postgres-like sequences, so a trigger and a helper table seem to be the only way in this case.

Therefore, I went on with the assumption that an autoincrement column might be unique anyway. What do you think?

Copy link
Member

@brandonpayton brandonpayton left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@brandonpayton Thanks for the in-depth feedback!

In MySQL, you can INSERT two different rows with the same id as long as name is different:
But in the SQLite scheme, it does not work because id is constrained to be unique on its own:

Yeah, it's definitely a limitation of this simple approach, but I think it's probably fine to keep this limitation, at least until we encounter some real-life scenario where this causes issues.

@JanJakes This sounds good. Thanks for explaining and discussing an alternative possibility.

I think this is good to go!

@JanJakes JanJakes merged commit 2d8d399 into develop Jan 9, 2026
16 checks passed
@JanJakes JanJakes deleted the compound-pk-autoincrement branch January 9, 2026 15:19
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants