Skip to main content
Database Design
CHAPTER 13 Beginner

SQL Database Constraints | NOT NULL, UNIQUE, CHECK

Updated: May 16, 2026
20 min read

# CHAPTER 13

Constraints and Data Integrity

1. Introduction

A database is only as valuable as the integrity of its data. If an E-Commerce database allows a user to register without an email address, or allows an order to be placed with a negative price, the entire application logic will collapse. Application code (like PHP or Python) often has bugs and misses validation checks. The database must be the final, unbreakable wall of defense. In SQL, we build these walls using Constraints.

2. Learning Objectives

By the end of this chapter, you will be able to:
  • Define the architectural purpose of Constraints.
  • Prevent missing data using NOT NULL.
  • Prevent duplicate data using the UNIQUE constraint.
  • Set fallback data using DEFAULT.
  • Enforce strict custom business rules using the CHECK constraint.

3. The NOT NULL Constraint

By default, if you don't provide data for a column during an INSERT, the database engine happily fills it with NULL (Empty). If an email is missing, the user cannot log in. We mathematically block this using NOT NULL.
sql
123456
CREATE TABLE users (
    id INT PRIMARY KEY,
    -- If an insert lacks a name or email, SQL throws a fatal error!
    name VARCHAR(100) NOT NULL,
    email VARCHAR(150) NOT NULL 
);

4. The UNIQUE Constraint

The Primary Key is unique by definition. But what if you have *other* columns that also must be unique? A user's username or email cannot be shared by two people.
sql
12345
CREATE TABLE users (
    id INT PRIMARY KEY,
    -- Cannot be empty, and mathematically cannot be a duplicate!
    email VARCHAR(150) NOT NULL UNIQUE 
);

5. The DEFAULT Constraint

When a user registers, their account shouldn't be verified immediately. Instead of forcing the Node.js backend to manually insert is_verified = FALSE on every single registration, we can tell SQL to set a default fallback value automatically.
sql
123456
CREATE TABLE users (
    id INT PRIMARY KEY,
    email VARCHAR(150) NOT NULL UNIQUE,
    -- Automatically FALSE unless the backend explicitly specifies otherwise
    is_verified BOOLEAN DEFAULT FALSE 
);

6. The CHECK Constraint (Custom Business Logic)

What if the business rule states: *"A product price cannot be negative, and an employee must be at least 18 years old"*? We can enforce custom mathematical logic directly on the database column using the CHECK constraint.
sql
123456789101112
CREATE TABLE products (
    product_id INT PRIMARY KEY,
    product_name VARCHAR(100) NOT NULL,
    
    -- The database will reject any INSERT or UPDATE where price is < 0!
    price DECIMAL(10,2) NOT NULL CHECK (price >= 0.00)
);

CREATE TABLE employees (
    emp_id INT PRIMARY KEY,
    age INT NOT NULL CHECK (age >= 18)
);

7. Mini Project: Secure User Database Schema

Let's combine all of our constraints to build a production-grade, enterprise-ready user table that is practically immune to corrupted application code.
sql
1234567891011121314151617181920
CREATE TABLE secure_users (
    -- The Mathematical Fingerprint
    user_id INT AUTO_INCREMENT PRIMARY KEY,
    
    -- Mandatory, Unique identifiers
    username VARCHAR(30) NOT NULL UNIQUE,
    email VARCHAR(150) NOT NULL UNIQUE,
    
    -- Optional data (No constraints)
    bio TEXT,
    
    -- Mandatory data with a secure fallback
    account_status VARCHAR(20) NOT NULL DEFAULT &#039;Pending',
    
    -- Ensuring usernames are at least 4 characters long!
    CONSTRAINT chk_username_length CHECK (LENGTH(username) >= 4),
    
    -- Auto-timestamping the registration
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);

8. Naming Your Constraints

In the mini-project above, notice the syntax: CONSTRAINT chk_username_length CHECK (...). While you can write constraints inline without a name, it is a severe anti-pattern. If you don't name your constraint, the database generates a random name like sys_chk_8932. If you ever want to delete that constraint in the future using ALTER TABLE, it is incredibly difficult to find. Always explicitly name your constraints!

9. Common Mistakes

  • Confusing UNIQUE with PRIMARY KEY: Beginners often ask, "Why not just make the Email the Primary Key since it is UNIQUE?" Primary Keys are used heavily in JOIN queries. Comparing integers (id = 5) is mathematically 100x faster than comparing strings (email = 'john@test.com'). Always use an integer Primary Key, and use a UNIQUE constraint for the string.

10. Best Practices

  • Double Validation: A common question is: "Should I validate the age in the JavaScript frontend, the Python backend, or the Database CHECK constraint?" The answer is All Three. The frontend for user experience, the backend for primary logic, and the Database as the final, absolute guarantee of Data Integrity.

11. Exercises

  1. 1. What constraint forces the database to automatically reject an INSERT command if the backend developer forgets to provide an email address?
  1. 2. What constraint allows you to enforce custom logical rules, such as ensuring a salary is greater than $30,000?

12. Database Design Challenges

Write the DDL SQL to create a Bank_Accounts table. It must have an auto-incrementing account_id, a user_id Foreign Key, and a balance column (Decimal). Implement a constraint that mathematically prevents the balance from ever dropping below $0.00. *(Answer: CREATE TABLE Bank_Accounts ( account_id INT AUTO_INCREMENT PRIMARY KEY, user_id INT, balance DECIMAL(10,2) NOT NULL CHECK (balance >= 0.00), FOREIGN KEY (user_id) REFERENCES Users(id) );)*

13. MCQ Quiz with Answers

Question 1

When defining a table schema, a Database Architect applies the UNIQUE and NOT NULL constraints to the license_number column. What happens if a backend application attempts to INSERT a new row without providing a license number?

Question 2

What is the primary architectural purpose of the CHECK constraint in SQL?

14. Interview Questions

  • Q: Explain the philosophical defense-in-depth strategy of utilizing Database Constraints (like NOT NULL and CHECK) even if the application backend (e.g., Express.js or Django) already has rigorous data validation middleware.
  • Q: Contrast the operational differences between the PRIMARY KEY constraint and the UNIQUE constraint. Can a single table have multiple UNIQUE columns? Can it have multiple PRIMARY KEY columns?

15. FAQs

Q: Do constraints slow down the database? A: Marginally. Every time you INSERT a row, the database must run the math to verify the CHECK and UNIQUE rules. This takes milliseconds. The tiny write-speed penalty is absolutely worth the guarantee of perfect Data Integrity.

16. Summary

Your database is now an impenetrable fortress. By defining explicit constraints, locking down mandatory fields with NOT NULL, preventing duplicates with UNIQUE, automating defaults, and enforcing business logic with CHECK, you guarantee that no bug in the application code can ever corrupt the structural integrity of your tables.

17. Next Chapter Recommendation

Our data is safe, structured, and normalized. But as our platform grows to millions of users, finding a specific user becomes agonizingly slow. In Chapter 14: Indexing and Query Performance, we will learn the ultimate dark art of database engineering: B-Tree Indexes.

Finish this Chapter

Save your progress on your learning path and prepare for coding interview challenges.

Discussion

Join the discussion

Log in or create a free account to participate.

Sort: ·