Constraints: keys, UNIQUE, CHECK & DEFAULT
PRIMARY KEY, FOREIGN KEY with ON DELETE/UPDATE, UNIQUE, NOT NULL, CHECK and DEFAULT.
A database's most valuable feature isn't storing data. It's refusing bad data. Constraints are rules attached to tables that MySQL enforces on every INSERT and UPDATE, no matter which application, script or person makes the change. Bugs in your code can't sneak invalid data past them.
NOT NULL and DEFAULT#
- Make columns
NOT NULLunless "unknown" is a real, meaningful state. That one habit removes a whole class of NULL bugs. - MySQL 8.0.13+ allows expression defaults in brackets, e.g.
DEFAULT (UUID())orDEFAULT (CURRENT_DATE + INTERVAL 30 DAY). ON UPDATE CURRENT_TIMESTAMPrefreshesupdated_atautomatically whenever the row changes.
PRIMARY KEY#
Every table should have a primary key. InnoDB physically stores rows in primary-key order (the clustered index), so the key is also the fastest way to find a row.
Surrogate keys (id INT AUTO_INCREMENT) never change and stay small. Natural keys (a country code, an ISBN) carry meaning but can change or turn out not to be unique after all. Most tables use a surrogate key, plus UNIQUE constraints on the natural identifiers.
UNIQUE#
- Naming constraints (
CONSTRAINT uq_members_email ...) gives readable error messages and makes them easy to drop later. UNIQUE (team, jersey)is a composite unique key: number 7 can appear once per team.- Multiple NULLs are allowed in a UNIQUE column, which is why two red players without a jersey number were fine.
FOREIGN KEY: relationships you can trust#
A foreign key says "this column's value must exist in that table's key". It needs InnoDB, matching column types, and an index on both sides (MySQL creates the child-side index automatically if it's missing).
Author 99 doesn't exist, so the insert is rejected. Deleting an author who still has posts is rejected too:
Referential actions
What should happen to children when the parent is deleted or its key changes?
Choose deliberately. CASCADE suits things that make no sense without their parent (an order's line items). RESTRICT protects important history (you shouldn't delete a customer who has invoices). SET NULL suits optional links (a post whose editor left the company).
Deleting post 1 removed its two comments automatically.
Bulk imports sometimes load tables out of order.
SET FOREIGN_KEY_CHECKS = 0;turns checking off for your session, but rows loaded meanwhile are not re-checked when you turn it back on. Use it only with data you trust, and always set it back to 1.
CHECK constraints#
A CHECK can compare several columns of the same row, but it can't use subqueries, other tables or non-deterministic functions like NOW(). A condition that evaluates to NULL passes, so combine CHECK with NOT NULL where needed. Remember: on MySQL before 8.0.16 (and some MariaDB versions), check clauses may be parsed but not enforced.
Adding and removing constraints later#
Adding a constraint to a table that already holds violating rows fails, so clean the data first. To list a table's constraints:
Common mistakes#
- Leaving integrity to the application only. Sooner or later a script, an admin or a second app writes to the same tables. Constraints protect everyone.
- Mismatched foreign-key types.
INTvsINT UNSIGNED, or different character sets, give error 3780 ("incompatible"). - CASCADE everywhere. One careless
DELETEcan wipe out large amounts of related data. Cascade only true "part-of" relationships. - Nullable columns by default. Start with
NOT NULLand relax it only when you must.
What's next#
With trustworthy related tables in place, it's time for the most important multi-table skill in SQL: JOINs.
Check your understanding
Quick quiz
1.A foreign key is declared
ON DELETE CASCADE. What happens when you delete a parent row?2.Since which MySQL version are CHECK constraints actually enforced?
3.How many NULLs can a UNIQUE column contain in MySQL?
Finished reading?
Mark this lesson complete to track your progress.