Coming from SQL Server, SQLite's type system confuses me: no int versus bigint distinction, columns declared INT accepting text and something special about INTEGER PRIMARY KEY I keep half reading about.
What is the actual model for integers here?
Coming from SQL Server, SQLite's type system confuses me: no int versus bigint distinction, columns declared INT accepting text and something special about INTEGER PRIMARY KEY I keep half reading about.
What is the actual model for integers here?
The confusion is fair because SQLite genuinely works differently: types belong to values rather than columns, with columns merely expressing preference. The integer story in four pieces:
The model, type affinity: a column declared INT, INTEGER or BIGINT gets INTEGER affinity, meaning it prefers to store integers and converts what looks convertible, but a value that cannot convert stores as it came, which is your text in an INT column. Affinity is a preference rather than a constraint, and SQL Server instincts about declared types enforcing themselves need CHECK constraints here, CHECK (typeof(col) = 'integer') being the strict translation. Recent SQLite offers STRICT tables enforcing types the familiar way, worth using in new schemas where the library version allows.
The storage, dynamic sizing: every integer value stores in 1, 2, 3, 4, 6 or 8 bytes chosen per value by magnitude, so declaring BIGINT buys nothing and small values in any integer column cost one byte plus overhead. The ceiling is the signed 64 bit range, matching bigint and everything integer in SQLite lives within it. Beyond that ceiling values silently become REAL floating point with the precision loss that implies, relevant to anyone storing 20 digit identifiers who should use TEXT instead.
The special one, INTEGER PRIMARY KEY: declared exactly as those two words, the column becomes an alias for the rowid, the table's internal 64 bit row identifier, making it the true auto assigned key with maximum lookup speed and no separate index. Declared as INT PRIMARY KEY instead, it does not alias the rowid, the single most surprising spelling sensitivity in the engine. AUTOINCREMENT on top changes only one behaviour, forbidding rowid reuse after deletes at a small cost, needed less often than habit suggests.
Booleans and the rest of the family: no boolean type exists, 0 and 1 integers by convention with TRUE and FALSE as literal aliases in modern versions. Dates as integers mean Unix epoch seconds by convention with the date functions converting, one of three date storage conventions SQLite leaves to the schema designer. All of it consistent once the values have types, columns have preferences model replaces the imported instincts.
The INT PRIMARY KEY versus INTEGER PRIMARY KEY spelling difference explains a performance mystery in our app dating back a year. Converted the table and lookups measurably improved. The values have types mental model finally made the whole engine click.