Why does SQLite insert duplicate composite primary keys? Why does SQLite insert duplicate composite primary keys? sqlite sqlite

Why does SQLite insert duplicate composite primary keys?


SQL PK (PRIMARY KEY) means UNIQUE NOT NULL. You shouldn't expect to be able to have a NULL in a value for a PK, let alone only one. You should declare PK columns NOT NULL and not put NULL in them.

SQL As Understood By SQLite:

Each row in a table with a primary key must have a unique combination of values in its primary key columns. For the purposes of determining the uniqueness of primary key values, NULL values are considered distinct from all other values, including other NULLs. If an INSERT or UPDATE statement attempts to modify the table content so that two or more rows have identical primary key values, that is a constraint violation.

According to the SQL standard, PRIMARY KEY should always imply NOT NULL. Unfortunately, due to a bug in some early versions, this is not the case in SQLite. Unless the column is an INTEGER PRIMARY KEY or the table is a WITHOUT ROWID table or the column is declared NOT NULL, SQLite allows NULL values in a PRIMARY KEY column. SQLite could be fixed to conform to the standard, but doing so might break legacy applications. Hence, it has been decided to merely document the fact that SQLite allowing NULLs in most PRIMARY KEY columns.

Since NULL in a PK is against SQL, it seems moot what SQLite then chooses to do when constraining and manipulating tables with NULLs in a PK. But it uses the usual SQL interpretation that NULL is not equal to NULL for purposes of UNIQUE. This is like when you declare a column set UNIQUE NULL. So as a constraint, SQLite PK is a synonym for UNIQUE instead of UNIQUE NOT NULL.

A UNIQUE constraint is similar to a PRIMARY KEY constraint, except that a single table may have any number of UNIQUE constraints. For each UNIQUE constraint on the table, each row must contain a unique combination of values in the columns identified by the UNIQUE constraint. For the purposes of UNIQUE constraints, NULL values are considered distinct from all other values, including other NULLs.


SQLite, like many other SQL databases, considers two NULLs as different values for the purposes of uniqueness (partially because, in SQL, NULL == NULL is false).

I don't believe there is a way to alter this behavior. As a workaround, you can use an empty string in column b as "no value".