By WebNest Studio Engineering Team
Database and SQL Tutorial
SQL Constraints
Constraints are rules attached to columns or tables that the database enforces automatically, rejecting any INSERT or UPDATE that would violate them. Constraints move data-validation logic out of individual applications and into the database itself, so the rule can never be bypassed no matter which application or script writes the data.
Why it matters
Application code has bugs, and data arrives from imports, scripts and other services that skip your checks entirely. Constraints are rules the database itself enforces on every write, whoever makes it. They are the last and most reliable line of defence for the correctness of your data.
Column-Level Constraints
These constraints apply to a single column's values.
NOT NULL— the column must always have a value; NULL is rejected.UNIQUE— no two rows may share the same value in this column (NULLs are typically exempt).CHECK (condition)— every value must satisfy a boolean expression, e.g.CHECK (price >= 0).DEFAULT value— supplies a value automatically when none is provided in an INSERT.
Table-Level Constraints
PRIMARY KEY and FOREIGN KEY can also be declared at the table level, which is required when they span multiple columns (a composite key) or when adding the constraint to an existing table after it was created. A FOREIGN KEY constraint can specify behavior on deletion of the referenced row, such as ON DELETE CASCADE (delete dependent rows automatically) or ON DELETE RESTRICT (block the deletion while dependents exist).
Why Constraints Matter
Without constraints, invalid data — a negative price, a duplicate username, an order pointing to a nonexistent customer — can silently enter the database through any bug in any application, script, or manual data fix. Constraints act as a last line of defense that holds regardless of which code path writes the data, catching mistakes at the moment they happen rather than as a corrupted row discovered weeks later.
Example
Combining NOT NULL, UNIQUE, CHECK, DEFAULT, and FOREIGN KEY on one table
CREATE TABLE accounts (
id INTEGER PRIMARY KEY,
username VARCHAR(50) NOT NULL UNIQUE,
balance DECIMAL(10, 2) NOT NULL DEFAULT 0.00 CHECK (balance >= 0),
referred_by INTEGER REFERENCES accounts(id) ON DELETE SET NULL
);
INSERT INTO accounts (id, username) VALUES (1, 'asha_r');
INSERT INTO accounts (id, username, balance) VALUES (2, 'asha_r', 50.00);
-- fails: username must be UNIQUE
First INSERT succeeds (balance defaults to 0.00). Second INSERT is rejected: duplicate value violates unique constraint on username.
Common Mistakes
- Assuming application-level validation (e.g., in a web form) is enough and skipping database constraints — any other script, migration, or bug can still insert bad data directly.
- Forgetting that a UNIQUE constraint usually allows multiple NULLs, since NULL is not considered equal to another NULL.
- Adding a CHECK constraint that references another table's data — CHECK can only validate values within the same row, not cross-table rules.
- Deleting a referenced row without considering ON DELETE behavior, causing an unexpected foreign key violation or unwanted cascading deletes.
Exercise
Create an accounts table in which email is required and unique, balance can never be negative, and status defaults to active. The three inserts below should then behave as follows: the first succeeds, the second is rejected as a duplicate email, and the third is rejected for its negative balance.
Expected output: email | balance | status then asha@example.com | 100 | active
-- TODO: accounts (id, email, balance, status) with the constraints described
INSERT INTO accounts (id, email, balance) VALUES (1, 'asha@example.com', 100);
INSERT INTO accounts (id, email, balance) VALUES (2, 'asha@example.com', 50);
INSERT INTO accounts (id, email, balance) VALUES (3, 'ravi@example.com', -20);
SELECT email, balance, status FROM accounts;
Show hints
- Use
NOT NULL UNIQUEon the email andCHECK (balance >= 0)on the balance. - A default is written
DEFAULT 'active'after the column type.
Show solution
CREATE TABLE accounts (
id INTEGER PRIMARY KEY,
email TEXT NOT NULL UNIQUE,
balance INTEGER NOT NULL CHECK (balance >= 0),
status TEXT NOT NULL DEFAULT 'active'
);
INSERT INTO accounts (id, email, balance) VALUES (1, 'asha@example.com', 100);
INSERT INTO accounts (id, email, balance) VALUES (2, 'asha@example.com', 50);
INSERT INTO accounts (id, email, balance) VALUES (3, 'ravi@example.com', -20);
SELECT email, balance, status FROM accounts;
Quick quiz
1. Which constraint rejects a row whose age is below 18?
- A. UNIQUE
- B. DEFAULT 18
- C. CHECK (age >= 18)
- D. NOT NULL
Show answer
C. A CHECK constraint evaluates a condition for every inserted or updated row.
2. What does DEFAULT do?
- A. Supplies a value when an INSERT does not give one for the column
- B. Rejects NULL values
- C. Makes the column unique
- D. Sorts the column
Show answer
A. An explicit value in the INSERT overrides the default.
3. Where is the most reliable place to enforce a rule such as "email must be unique"?
- A. In the front-end form
- B. In a comment
- C. In the application code only
- D. In the database, as a constraint
Show answer
D. Two simultaneous requests can both pass an application check; only the database can guarantee uniqueness.
Interview questions
What kinds of constraint does SQL provide?
Show answer
NOT NULL requires a value. UNIQUE forbids duplicate values. PRIMARY KEY combines the two and identifies the row. FOREIGN KEY requires the value to exist in another table. CHECK requires a condition to be true for the row. DEFAULT, though not strictly a constraint, supplies a value when none is given.
If the application already validates the data, why add constraints?
Show answer
Because the application is not the only way data gets in. Bugs, direct SQL fixes, import scripts, background jobs and other services all write to the database without passing through the same validation. Some rules, such as uniqueness, cannot be enforced reliably from application code at all when requests run concurrently. Constraints guarantee the rule for every write, and they also document it.
Key Points to Remember
- NOT NULL, UNIQUE, CHECK, and DEFAULT are the core column-level constraints for enforcing data validity.
- PRIMARY KEY and FOREIGN KEY constraints enforce identity and relationships between tables.
- ON DELETE CASCADE/RESTRICT/SET NULL controls what happens to dependent rows when a referenced row is deleted.
- Constraints enforce rules at the database level, independent of which application or script writes the data.
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