Skip to main content

Primary Keys

Every durable table needs a stable way to identify one row from all others.

That is the job of the primary key.

Core Concepts

flowchart TD
A[Table rows] --> B[Primary key column(s)]
B --> C[Unique row identity]
C --> D[Reliable references from other tables]
Primary key styleExampleUse case
Single-column keyid INTEGER PRIMARY KEYMost app tables
Composite keyPRIMARY KEY (student_id, course_id)Join/association tables

Code Examples

-- Single-column primary key.
CREATE TABLE users (
user_id INTEGER PRIMARY KEY,
name TEXT NOT NULL
);
Expected output
Table users is created successfully.
-- Composite primary key example.
CREATE TABLE enrollments (
student_id INTEGER,
course_id INTEGER,
enrolled_on TEXT,
PRIMARY KEY (student_id, course_id)
);
Expected output
Table enrollments is created with composite primary key.
-- Inspect key markers in metadata.
PRAGMA table_info(enrollments);
cidnametypenotnulldflt_valuepk
0student_idINTEGER0null1
1course_idINTEGER0null2
2enrolled_onTEXT0null0

SQLite-Specific Nuances

SQLite Nuance

INTEGER PRIMARY KEY has special behavior in SQLite: it aliases the internal row identifier.

This makes it efficient and a strong default choice for many tables.

Common Pitfalls / Best Practices

Pitfall

Skipping primary keys in early prototypes and trying to retrofit identity later.

That often creates messy migrations and duplicate row problems.

Best Practice

Always define a primary key when creating a table, even for temporary learning schemas.

Quick Challenge

Create a departments table with:

  • department_id as primary key
  • name as required text
View Solution
CREATE TABLE departments (
department_id INTEGER PRIMARY KEY,
name TEXT NOT NULL
);
Expected output
Table is created with a single-column primary key.