NULL Handling in UNIQUE Constraints
Control whether multiple NULL values are treated as distinct (allowed) or not distinct (only one NULL permitted) in a UNIQUE constraint.
NULLS DISTINCT NULLS NOT DISTINCT NULL in UNIQUE unique NULL SQL:2023
UNIQUE NULL constraint NULLS DISTINCT SQL standard
| Database | Status | Syntax Family | Min Version |
|---|---|---|---|
| PostgreSQL | full | sql-standard | 15 |
| MySQL | partial | - | - |
| MariaDB | partial | - | - |
| Oracle | partial | - | - |
| SQL Server | partial | - | - |
| SQLite | partial | - | - |
| Redshift | partial | - | - |
| DB2 | partial | - | - |
| Snowflake | partial | - | - |
| BigQuery | none | - | - |
Compare Databases
Database Details
PostgreSQL
full
-- Default: multiple NULLs are allowed (NULLS DISTINCT)
CREATE TABLE users (
id INT PRIMARY KEY,
email TEXT UNIQUE
);
-- PostgreSQL 15+: allow only one NULL
CREATE TABLE users (
id INT PRIMARY KEY,
email TEXT UNIQUE NULLS NOT DISTINCT
);
-- Also works on a named constraint or index
CREATE UNIQUE INDEX idx_users_email
ON users (email) NULLS NOT DISTINCT;- Pre-15: multiple NULLs always allowed.
- 15+: NULLS NOT DISTINCT caps the column at one NULL. Also works on CREATE UNIQUE INDEX.
MySQL
partial
-- Multiple NULLs are always permitted in a UNIQUE index
CREATE TABLE users (
id INT PRIMARY KEY,
email VARCHAR(255) UNIQUE
);
INSERT INTO users (id, email) VALUES (1, NULL);
INSERT INTO users (id, email) VALUES (2, NULL); -- succeeds- Multiple NULLs always allowed; no knob to change it.
Docs: CREATE INDEX - UNIQUE
MariaDB
partial
-- Same as MySQL: multiple NULLs always allowed
CREATE TABLE users (
id INT PRIMARY KEY,
email VARCHAR(255) UNIQUE
);- Same as MySQL: multiple NULLs always allowed, no knob.
Docs: UNIQUE Index
Oracle
partial
-- Multiple NULLs are always allowed
CREATE TABLE users (
id NUMBER PRIMARY KEY,
email VARCHAR2(255) UNIQUE
);
-- Workaround: unique function-based index that treats NULLs as a sentinel
CREATE UNIQUE INDEX idx_users_email_nn
ON users (CASE WHEN email IS NOT NULL THEN email END);- Multiple NULLs always allowed. To emulate NULLS NOT DISTINCT, build a function-based index that maps NULL to a sentinel, e.g. CASE WHEN col IS NULL THEN 0 ELSE 1 END.
Docs: Constraints
SQL Server
partial
-- SQL Server UNIQUE allows at most one NULL per column
CREATE TABLE users (
id INT PRIMARY KEY,
email NVARCHAR(255) UNIQUE
);
-- Workaround: filtered unique index allows many NULLs while enforcing uniqueness on non-NULL values
CREATE UNIQUE INDEX idx_users_email
ON users (email)
WHERE email IS NOT NULL;- Default is one NULL allowed per column — the opposite of SQL:2003.
- CREATE UNIQUE INDEX ... WHERE col IS NOT NULL gives many NULLs plus unique non-NULLs.
SQLite
partial
-- Multiple NULLs are always allowed
CREATE TABLE users (
id INTEGER PRIMARY KEY,
email TEXT UNIQUE
);- Multiple NULLs always allowed. Use CREATE UNIQUE INDEX ... WHERE col IS NOT NULL for NULLS NOT DISTINCT-style behavior.
Docs: CREATE TABLE - UNIQUE
DB2
partial
-- Multiple NULLs allowed; Db2 treats NULL as distinct in UNIQUE indexes
CREATE TABLE users (
id INTEGER NOT NULL PRIMARY KEY,
email VARCHAR(255) UNIQUE
);- Multiple NULLs always allowed. For strict single-value uniqueness, make the column NOT NULL.
Docs: UNIQUE Constraint