Database constraints and data validation

Maria Garcia Feb 2026
2 tabs
-- Primary key (unique, not null identifier)
CREATE TABLE users (
  id SERIAL PRIMARY KEY,
  username VARCHAR(50) NOT NULL,
  email VARCHAR(100) NOT NULL
);

-- Composite primary key
CREATE TABLE user_roles (
  user_id INT,
  role_id INT,
  PRIMARY KEY (user_id, role_id)
);

-- Foreign key (referential integrity)
CREATE TABLE orders (
  id SERIAL PRIMARY KEY,
  user_id INT NOT NULL REFERENCES users(id),
  product_id INT REFERENCES products(id) ON DELETE SET NULL,
  created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);

-- Foreign key actions
-- ON DELETE CASCADE: Delete child rows when parent deleted
-- ON DELETE SET NULL: Set foreign key to NULL
-- ON DELETE RESTRICT: Prevent deletion if children exist (default)
-- ON DELETE NO ACTION: Same as RESTRICT
-- ON UPDATE CASCADE: Update child rows when parent key changes

CREATE TABLE comments (
  id SERIAL PRIMARY KEY,
  post_id INT NOT NULL,
  user_id INT NOT NULL,
  content TEXT NOT NULL,
  FOREIGN KEY (post_id) REFERENCES posts(id) ON DELETE CASCADE,
  FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE
);

-- UNIQUE constraint
CREATE TABLE users (
  id SERIAL PRIMARY KEY,
  username VARCHAR(50) UNIQUE NOT NULL,
  email VARCHAR(100) UNIQUE NOT NULL
);

-- Named unique constraint
ALTER TABLE users
  ADD CONSTRAINT users_email_unique UNIQUE (email);

-- Composite unique constraint
CREATE TABLE user_preferences (
  user_id INT,
  preference_key VARCHAR(50),
  preference_value TEXT,
  UNIQUE (user_id, preference_key)
);

-- NOT NULL constraint
ALTER TABLE users
  ALTER COLUMN email SET NOT NULL;

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

-- DEFAULT values
CREATE TABLE posts (
  id SERIAL PRIMARY KEY,
  title VARCHAR(200) NOT NULL,
  status VARCHAR(20) DEFAULT 'draft',
  views INT DEFAULT 0,
  is_published BOOLEAN DEFAULT false,
  created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
  updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);

-- Add default to existing column
ALTER TABLE posts
  ALTER COLUMN status SET DEFAULT 'draft';

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

-- CHECK constraints (data validation)
CREATE TABLE products (
  id SERIAL PRIMARY KEY,
  name VARCHAR(100) NOT NULL,
  price DECIMAL(10,2) CHECK (price > 0),
  discount_pct INT CHECK (discount_pct BETWEEN 0 AND 100),
  stock INT CHECK (stock >= 0),
  status VARCHAR(20) CHECK (status IN ('active', 'discontinued', 'out_of_stock'))
);

-- Named CHECK constraint
ALTER TABLE products
  ADD CONSTRAINT price_positive CHECK (price > 0);

-- Multi-column CHECK constraint
CREATE TABLE events (
  id SERIAL PRIMARY KEY,
  start_time TIMESTAMP NOT NULL,
  end_time TIMESTAMP NOT NULL,
  CHECK (end_time > start_time)
);

-- Complex CHECK constraint
CREATE TABLE employees (
  id SERIAL PRIMARY KEY,
  name VARCHAR(100) NOT NULL,
  hire_date DATE NOT NULL,
  termination_date DATE,
  salary DECIMAL(10,2) CHECK (salary > 0),
  CHECK (termination_date IS NULL OR termination_date > hire_date)
);

-- Drop constraint
ALTER TABLE products
  DROP CONSTRAINT price_positive;

-- Disable constraint (PostgreSQL)
-- Not directly supported, but can use trigger approach

-- View constraints
SELECT
  conname AS constraint_name,
  contype AS constraint_type,
  pg_get_constraintdef(oid) AS definition
FROM pg_constraint
WHERE conrelid = 'products'::regclass;
2 files · sql Explain with highlit

Constraints enforce data integrity at the database level. PRIMARY KEY ensures uniqueness and identifies rows. FOREIGN KEY maintains referential integrity. NOT NULL prevents null values. UNIQUE prevents duplicates. CHECK validates data conditions. DEFAULT provides fallback values. I use constraints to prevent invalid data—application bugs can't bypass database rules. Constraints document business rules. Understanding constraint violations guides error handling. Deferrable constraints postpone validation until transaction commit. Exclusion constraints prevent overlapping ranges. Domain constraints reuse validation logic. Constraints are defense against data corruption. Proper constraints reduce application validation code and ensure data quality.