By WebNest Studio Engineering Team
Database and SQL Tutorial
Keys: Primary, Foreign, and Composite
Keys are how a relational database uniquely identifies rows and links related tables together. Without keys, there is no reliable way to say "this row" versus "that row," nor any way to connect an order to the customer who placed it. Keys are the backbone of both data integrity and the ability to join tables meaningfully.
Why it matters
Keys are what make a relational database relational. A primary key identifies each row, and a foreign key links a row in one table to a row in another and stops the link from pointing at nothing. Without them, a database fills up with duplicate records and orders that belong to customers who do not exist.
Primary Keys
A primary key is one column (or a combination of columns) that uniquely identifies every row in a table. A primary key column is implicitly NOT NULL and must be unique across all rows. Every table should have exactly one primary key, and most database engines automatically create an index on it to make lookups by that key fast.
Foreign Keys
A foreign key is a column in one table that references the primary key of another table, establishing a relationship between them. For example, an orders table might have a customer_id column that is a foreign key referencing customers.id. The database enforces referential integrity: it will reject an insert that references a customer_id that doesn't exist, and by default it will also reject deleting a customer who still has orders (unless cascading behavior is configured).
Composite Keys
A composite key is a primary (or unique) key made of two or more columns together, used when no single column is unique on its own. A common example is a join table like enrollments(student_id, course_id), where the combination of student and course is unique even though neither column alone is.
Surrogate Keys vs. Natural Keys
A natural key is an existing real-world attribute used as the primary key, such as an email address or a national ID number. A surrogate key is an artificial, meaningless identifier — typically an auto-incrementing integer or a UUID — introduced purely to serve as a stable primary key. Surrogate keys are generally preferred in practice because natural keys can change over time (a person can change their email) or turn out not to be as unique as assumed, which would force painful changes to every foreign key referencing them.
Example
A primary key, a foreign key, and a composite key together
CREATE TABLE customers (
id INTEGER PRIMARY KEY, -- surrogate key
email VARCHAR(150) UNIQUE NOT NULL -- natural candidate key, kept unique but not primary
);
CREATE TABLE orders (
id INTEGER PRIMARY KEY,
customer_id INTEGER NOT NULL REFERENCES customers(id), -- foreign key
order_date DATE NOT NULL
);
CREATE TABLE order_items (
order_id INTEGER REFERENCES orders(id),
product_id INTEGER,
quantity INTEGER NOT NULL,
PRIMARY KEY (order_id, product_id) -- composite key
);
All three CREATE TABLE statements succeed; order_items enforces one row per (order_id, product_id) pair.
Common Mistakes
- Using a "natural" identifier like email or phone number as a primary key, then struggling when that value legitimately needs to change.
- Forgetting to index foreign key columns, which are frequently used in JOIN conditions and WHERE filters, causing slow queries as tables grow.
- Trying to insert a foreign key value that doesn't exist in the referenced table and being surprised by a constraint violation error.
- Believing a table can have multiple primary keys instead of one primary key that may itself be composed of multiple columns.
Exercise
Create a customers table with a primary key, and an orders table whose customer_id is a foreign key to it. Insert customer 1, Asha. Insert an order for customer 1, then try to insert an order for customer 99, who does not exist; the database must reject it. Finally count the orders as total.
Expected output: total then 1
-- TODO: customers (id primary key, name)
-- TODO: orders (id primary key, customer_id referencing customers, product)
INSERT INTO customers (id, name) VALUES (1, 'Asha');
INSERT INTO orders (id, customer_id, product) VALUES (1, 1, 'pen');
INSERT INTO orders (id, customer_id, product) VALUES (2, 99, 'bag');
SELECT COUNT(*) AS total FROM orders;
Show hints
- A foreign key is declared on the column:
customer_id INTEGER REFERENCES customers(id). - The third insert should fail with a foreign key error, leaving one order.
Show solution
CREATE TABLE customers (
id INTEGER PRIMARY KEY,
name TEXT NOT NULL
);
CREATE TABLE orders (
id INTEGER PRIMARY KEY,
customer_id INTEGER NOT NULL REFERENCES customers(id),
product TEXT
);
INSERT INTO customers (id, name) VALUES (1, 'Asha');
INSERT INTO orders (id, customer_id, product) VALUES (1, 1, 'pen');
INSERT INTO orders (id, customer_id, product) VALUES (2, 99, 'bag');
SELECT COUNT(*) AS total FROM orders;
Quick quiz
1. Which two properties must a primary key have?
- A. Numeric and sorted
- B. Unique and not null
- C. Text and indexed
- D. Short and encrypted
Show answer
B. Every row must have a value, and no two rows may share one.
2. What does a foreign key guarantee?
- A. That the column is unique
- B. That the column is never null
- C. That the table is sorted
- D. That each value matches an existing row in the referenced table
Show answer
D. This is called referential integrity.
3. What is a composite key?
- A. A key made of two or more columns together
- B. A key that is encrypted
- C. A key shared by two tables
- D. A key generated by the database
Show answer
A. A junction table for a many-to-many relationship commonly uses one.
Interview questions
What is the difference between a primary key and a unique key?
Show answer
Both enforce uniqueness. A table can have only one primary key, and its columns cannot contain NULL; it is the main identifier of a row and the usual target of foreign keys. A table can have several unique constraints, and their columns may allow NULL. A typical table has a primary key on id and a unique constraint on something like email.
What is the difference between a natural key and a surrogate key?
Show answer
A natural key is a value with real-world meaning that happens to be unique, such as an email address or a national identity number. A surrogate key is an artificial identifier with no meaning, such as an auto-incremented integer or a UUID. Surrogate keys are usually preferred as primary keys because real-world values can change or turn out not to be unique; the natural key is then protected with a unique constraint.
Key Points to Remember
- A primary key uniquely and non-null identifies each row in a table.
- A foreign key references another table's primary key and enforces referential integrity between them.
- A composite key combines two or more columns when no single column is unique on its own.
- Surrogate keys (auto-generated, meaningless) are usually safer long-term than natural keys (real-world values that can change).
Practice in the playground
Write and run your own code for this topic, or start from the exercise or an example. Runs your SQL on SQLite in your browser. Standard SQL works; a few features that exist only in PostgreSQL or MySQL do not. Your code for each topic is kept in this browser.
Run the examples
Change an input, predict the result, then compare it with the output. Explain why the result changes.
These examples need a project environment on your computer, so they can be copied but not run here. Codelab runs Python, FastAPI backends with SQLite, plain Java 17 and HTML/CSS/JavaScript.
Written by
WebNest Studio Engineering Team
Practical lessons from developers working with Java, Python, React, databases and production systems.
Led by Vansh Duggal, Founder, WebNest Studio · Full-stack & software engineering