SQL Cheatsheet

Constraints

Use this SQL reference while you build software engineering projects, review code for technical interview prep, or polish examples for a software engineer resume.

Constraint Types Overview

ConstraintPurpose
NOT NULLColumn must have a value
UNIQUENo duplicate values (NULLs are allowed and not compared to each other)
PRIMARY KEYUniquely identifies each row; implies NOT NULL + UNIQUE
FOREIGN KEYEnforces referential integrity between tables
CHECKValidates values against a boolean expression
DEFAULTProvides a default value when none is supplied
GENERATEDComputed column value derived from other columns

Constraints can be column-level (inline) or table-level (separate clause, required for multi-column constraints).

NOT NULL

-- Column-level
CREATE TABLE users (
    id    INTEGER     NOT NULL,
    email VARCHAR(255) NOT NULL,
    phone VARCHAR(20)            -- nullable (default)
);

-- Add NOT NULL later
ALTER TABLE users ALTER COLUMN phone SET NOT NULL;

-- Remove NOT NULL
ALTER TABLE users ALTER COLUMN phone DROP NOT NULL;

-- Note: NOT NULL cannot be named (no constraint name); it is not a named constraint.

PRIMARY KEY

-- Single-column primary key (column-level)
CREATE TABLE users (
    id SERIAL PRIMARY KEY,
    email TEXT NOT NULL
);

-- Multi-column primary key (table-level only)
CREATE TABLE order_items (
    order_id   INTEGER NOT NULL,
    product_id INTEGER NOT NULL,
    qty        INTEGER NOT NULL,
    PRIMARY KEY (order_id, product_id)
);

-- Named primary key
CREATE TABLE users (
    id SERIAL,
    CONSTRAINT pk_users PRIMARY KEY (id)
);

-- Add primary key to existing table
ALTER TABLE products ADD PRIMARY KEY (id);
ALTER TABLE products ADD CONSTRAINT pk_products PRIMARY KEY (id);

-- Drop primary key
ALTER TABLE products DROP CONSTRAINT pk_products;
ALTER TABLE products DROP PRIMARY KEY;         -- MySQL shorthand

UNIQUE

-- Single column unique (column-level)
CREATE TABLE users (
    email VARCHAR(255) UNIQUE
);

-- Named unique constraint (column or table level)
CREATE TABLE users (
    email VARCHAR(255),
    CONSTRAINT uq_users_email UNIQUE (email)
);

-- Multi-column unique (table-level — combination must be unique)
CREATE TABLE team_members (
    team_id INTEGER NOT NULL,
    user_id INTEGER NOT NULL,
    CONSTRAINT uq_team_user UNIQUE (team_id, user_id)
);

-- Add unique constraint later
ALTER TABLE users ADD CONSTRAINT uq_email UNIQUE (email);

-- Drop unique constraint
ALTER TABLE users DROP CONSTRAINT uq_email;

-- NULL behavior: SQL standard says NULLs are not equal, so multiple NULLs
-- are allowed in a UNIQUE column. (SQL Server <= 2019 allows only one NULL
-- unless filtered index is used.)

FOREIGN KEY

-- Basic foreign key
CREATE TABLE orders (
    id      SERIAL PRIMARY KEY,
    user_id INTEGER NOT NULL,
    FOREIGN KEY (user_id) REFERENCES users(id)
);

-- Inline (column-level) shorthand
CREATE TABLE orders (
    id      SERIAL PRIMARY KEY,
    user_id INTEGER NOT NULL REFERENCES users(id)
);

-- Named foreign key
CREATE TABLE orders (
    id      SERIAL,
    user_id INTEGER NOT NULL,
    CONSTRAINT fk_orders_user FOREIGN KEY (user_id) REFERENCES users(id)
);

-- Multi-column foreign key
CREATE TABLE order_items (
    id         SERIAL PRIMARY KEY,
    order_id   INTEGER NOT NULL,
    product_id INTEGER NOT NULL,
    CONSTRAINT fk_order_items_order
        FOREIGN KEY (order_id, product_id)
        REFERENCES order_products(order_id, product_id)
);

-- Add foreign key to existing table
ALTER TABLE orders
ADD CONSTRAINT fk_user FOREIGN KEY (user_id) REFERENCES users(id);

-- Drop foreign key
ALTER TABLE orders DROP CONSTRAINT fk_user;
ALTER TABLE orders DROP FOREIGN KEY fk_user;  -- MySQL syntax

ON DELETE / ON UPDATE Actions

ActionDescription
RESTRICTError if referenced row would be deleted/updated (default, checked immediately)
NO ACTIONLike RESTRICT but checked at end of statement (SQL standard default)
CASCADEPropagate delete/update to child rows
SET NULLSet FK columns to NULL on parent delete/update
SET DEFAULTSet FK columns to their default on parent delete/update
-- Delete user → cascade-delete their orders
FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE

-- Delete category → set products.category_id to NULL
FOREIGN KEY (category_id) REFERENCES categories(id)
    ON DELETE SET NULL
    ON UPDATE CASCADE

-- Prevent deleting a user who has orders
FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE RESTRICT

-- Full example
CREATE TABLE comments (
    id        SERIAL PRIMARY KEY,
    post_id   INTEGER NOT NULL,
    parent_id INTEGER,
    body      TEXT NOT NULL,
    FOREIGN KEY (post_id)   REFERENCES posts(id)    ON DELETE CASCADE,
    FOREIGN KEY (parent_id) REFERENCES comments(id) ON DELETE CASCADE
);

CHECK Constraints

-- Column-level check
CREATE TABLE products (
    price    DECIMAL(10,2) CHECK (price >= 0),
    discount DECIMAL(5,2)  CHECK (discount BETWEEN 0 AND 100)
);

-- Named check constraint
CREATE TABLE products (
    price DECIMAL(10,2),
    CONSTRAINT chk_price_positive CHECK (price >= 0)
);

-- Multi-column check (table-level)
CREATE TABLE discounts (
    start_date DATE NOT NULL,
    end_date   DATE NOT NULL,
    CONSTRAINT chk_dates CHECK (end_date > start_date)
);

-- Regex / IN pattern (for string enumeration)
CREATE TABLE users (
    status VARCHAR(20),
    CONSTRAINT chk_status CHECK (status IN ('active','inactive','banned','pending'))
);

-- Add check constraint to existing table
ALTER TABLE products ADD CONSTRAINT chk_qty CHECK (stock >= 0);

-- Drop check constraint
ALTER TABLE products DROP CONSTRAINT chk_qty;

-- Note: MySQL parses but historically ignores CHECK constraints before 8.0.16

DEFAULT Constraint

-- Inline default
CREATE TABLE events (
    id         SERIAL PRIMARY KEY,
    title      TEXT NOT NULL,
    created_at TIMESTAMP    DEFAULT NOW(),
    is_public  BOOLEAN      DEFAULT TRUE,
    status     VARCHAR(20)  DEFAULT 'draft',
    views      INTEGER      DEFAULT 0
);

-- Named default (SQL Server)
CREATE TABLE events (
    status VARCHAR(20) CONSTRAINT df_status DEFAULT 'draft'
);

-- Add default to existing column
ALTER TABLE users ALTER COLUMN status SET DEFAULT 'active';       -- PostgreSQL
ALTER TABLE users ALTER COLUMN status SET DEFAULT 'active';       -- works in most
ALTER TABLE users MODIFY COLUMN status VARCHAR(20) DEFAULT 'active'; -- MySQL

-- Remove default
ALTER TABLE users ALTER COLUMN status DROP DEFAULT;

GENERATED / Computed Columns

-- PostgreSQL: GENERATED ALWAYS AS ... STORED
CREATE TABLE employees (
    first_name TEXT NOT NULL,
    last_name  TEXT NOT NULL,
    full_name  TEXT GENERATED ALWAYS AS (first_name || ' ' || last_name) STORED
);

-- Cannot INSERT/UPDATE generated columns directly

-- MySQL 5.7+: GENERATED ALWAYS AS ... STORED or VIRTUAL
CREATE TABLE circles (
    radius DOUBLE NOT NULL,
    area   DOUBLE GENERATED ALWAYS AS (PI() * radius * radius) STORED,
    circumference DOUBLE GENERATED ALWAYS AS (2 * PI() * radius) VIRTUAL
);
-- STORED: computed once and persisted; VIRTUAL: recomputed on read (not stored)

-- SQL Server: AS ... PERSISTED
CREATE TABLE employees (
    first_name NVARCHAR(50),
    last_name  NVARCHAR(50),
    full_name  AS (first_name + ' ' + last_name) PERSISTED
);

Constraint Naming and Management

-- List constraints on a table (PostgreSQL)
SELECT conname, contype, pg_get_constraintdef(oid)
FROM pg_constraint
WHERE conrelid = 'users'::regclass;

-- Information schema (standard, most DBs)
SELECT constraint_name, constraint_type
FROM information_schema.table_constraints
WHERE table_name = 'users';

-- Rename a constraint (PostgreSQL)
ALTER TABLE users RENAME CONSTRAINT uq_email TO uq_users_email;

-- Validate a previously NOT VALID constraint (PostgreSQL)
-- Add without scanning existing rows (fast on large tables):
ALTER TABLE orders ADD CONSTRAINT fk_user
    FOREIGN KEY (user_id) REFERENCES users(id)
    NOT VALID;
-- Then validate in background:
ALTER TABLE orders VALIDATE CONSTRAINT fk_user;

-- Disable / enable constraints (MySQL)
SET FOREIGN_KEY_CHECKS = 0;
-- ... bulk load ...
SET FOREIGN_KEY_CHECKS = 1;

-- Deferred constraints (PostgreSQL)
-- DEFERRABLE: can be deferred within a transaction
-- INITIALLY DEFERRED: deferred by default
-- INITIALLY IMMEDIATE: checked immediately by default (can be deferred per-transaction)
CREATE TABLE orders (
    id      SERIAL PRIMARY KEY,
    user_id INTEGER NOT NULL,
    CONSTRAINT fk_user FOREIGN KEY (user_id) REFERENCES users(id)
        DEFERRABLE INITIALLY DEFERRED
);

-- Defer within a transaction
BEGIN;
SET CONSTRAINTS fk_user DEFERRED;
-- ... do work that temporarily violates the FK ...
COMMIT;   -- FK checked here

Exclusion Constraints (PostgreSQL)

Generalize UNIQUE: ensure that no two rows satisfy a given operator-based condition.

-- Requires: CREATE EXTENSION IF NOT EXISTS btree_gist;

-- No two bookings for the same room overlap in time
CREATE TABLE bookings (
    room_id  INTEGER NOT NULL,
    during   TSRANGE NOT NULL,
    EXCLUDE USING GIST (room_id WITH =, during WITH &&)
);

-- &&: range overlap operator
-- =: equality