How to drop all NOT NULL constraints from a PostgreSQL table in one go
How to Drop All NOT NULL Constraints from a PostgreSQL Table in One Go

Learn how to efficiently remove all NOT NULL constraints from columns within a specific PostgreSQL table using generated SQL statements.
PostgreSQL's NOT NULL constraints are crucial for data integrity, ensuring that specified columns always contain a value. However, there are scenarios, such as data migration, schema refactoring, or temporary data loading, where you might need to temporarily or permanently remove these constraints from multiple columns in a table. Manually dropping each constraint can be tedious and error-prone, especially for tables with many columns. This article provides a robust method to generate and execute SQL commands to drop all NOT NULL constraints for a given table in a single operation.
Understanding NOT NULL Constraints in PostgreSQL
In PostgreSQL, a NOT NULL constraint is a column-level constraint that prevents NULL values from being stored in that column. When you define a column as NOT NULL, the database system enforces this rule for every INSERT or UPDATE operation. If an attempt is made to insert NULL into a NOT NULL column, the operation will fail with an error.
Unlike PRIMARY KEY or UNIQUE constraints, NOT NULL constraints are not named objects in the same way. They are attributes of the column definition itself. Therefore, to remove a NOT NULL constraint, you don't drop a constraint by name; instead, you ALTER the column to allow NULL values.
flowchart TD
A[Start] --> B{Identify Target Table}
B --> C{Query pg_catalog.pg_attribute}
C --> D{Filter for NOT NULL Columns}
D --> E{Generate ALTER TABLE Statement for Each Column}
E --> F{Concatenate Statements}
F --> G[Execute Generated SQL]
G --> H[End]Process flow for dropping NOT NULL constraints
Generating SQL to Drop NOT NULL Constraints
The key to dropping all NOT NULL constraints efficiently is to dynamically generate the ALTER TABLE ... ALTER COLUMN ... DROP NOT NULL; statements. We can achieve this by querying PostgreSQL's system catalogs, specifically pg_catalog.pg_attribute and pg_catalog.pg_class.
pg_catalog.pg_attribute contains information about table columns, including whether a column is NOT NULL. pg_catalog.pg_class provides metadata about tables, such as their names and OIDs (Object Identifiers). By joining these two, we can identify all NOT NULL columns for a specific table.
SELECT
'ALTER TABLE ' || c.relname || ' ALTER COLUMN ' || a.attname || ' DROP NOT NULL;' AS sql_command
FROM
pg_catalog.pg_attribute a
JOIN
pg_catalog.pg_class c ON a.attrelid = c.oid
WHERE
c.relname = 'your_table_name' -- Replace with your table name
AND a.attnotnull = true
AND a.attnum > 0
AND NOT a.attisdropped
ORDER BY
a.attnum;
SQL query to generate DROP NOT NULL statements
Let's break down this query:
pg_catalog.pg_attribute a: This aliasarefers to the system catalog table that stores information about table columns.pg_catalog.pg_class c: This aliascrefers to the system catalog table that stores information about tables.a.attrelid = c.oid: This join condition links columns to their respective tables using the Object ID.c.relname = 'your_table_name': This filters for the specific table you want to modify. Remember to replace'your_table_name'with the actual name of your table.a.attnotnull = true: This crucial condition filters for columns that currently have theNOT NULLconstraint.a.attnum > 0: This excludes system columns (which haveattnum <= 0).NOT a.attisdropped: This ensures we only consider columns that have not been dropped.ORDER BY a.attnum: Orders the generated statements by column position, which is good practice but not strictly necessary for correctness.
NOT NULL constraints can lead to data integrity issues if NULL values are subsequently inserted where they shouldn't be.Executing the Generated SQL
Once you have the generated SQL commands, you have a few options for execution:
- Copy and Paste: Run the
SELECTquery in your SQL client (e.g.,psql, DBeaver, pgAdmin). Copy the output (thesql_commandcolumn) and paste it back into the client to execute theALTER TABLEstatements. - Using
psql's\gexec: If you are using thepsqlcommand-line client, you can directly execute the generated commands. This is the most convenient method. - Scripting: Incorporate the generation and execution into a shell script or a programming language script for automation.
-- Example using psql's \gexec
SELECT
'ALTER TABLE ' || c.relname || ' ALTER COLUMN ' || a.attname || ' DROP NOT NULL;' AS sql_command
FROM
pg_catalog.pg_attribute a
JOIN
pg_catalog.pg_class c ON a.attrelid = c.oid
WHERE
c.relname = 'my_users_table' -- Replace with your table name
AND a.attnotnull = true
AND a.attnum > 0
AND NOT a.attisdropped
ORDER BY
a.attnum
\gexec
Executing generated SQL directly with psql's \gexec
"MyTable"). The relname and attname from pg_catalog are typically unquoted, so the generated SQL will also be unquoted. If your table was created with mixed-case or special characters, you'll need to adjust the c.relname filter and potentially the output quoting.Re-adding NOT NULL Constraints
After performing your operations, you might want to re-add the NOT NULL constraints. The process is similar, but you'll use SET NOT NULL instead of DROP NOT NULL. Before re-adding, ensure that no NULL values have been introduced into the columns, as this will cause the ALTER TABLE ... SET NOT NULL command to fail.
To re-add, you would use a query like this:
SELECT
'ALTER TABLE ' || c.relname || ' ALTER COLUMN ' || a.attname || ' SET NOT NULL;' AS sql_command
FROM
pg_catalog.pg_attribute a
JOIN
pg_catalog.pg_class c ON a.attrelid = c.oid
WHERE
c.relname = 'your_table_name' -- Replace with your table name
AND a.attnotnull = false -- Look for columns that are currently nullable
AND a.attnum > 0
AND NOT a.attisdropped
ORDER BY
a.attnum;
SQL query to generate SET NOT NULL statements
Note the change to a.attnotnull = false in the WHERE clause, as we are now looking for columns that currently allow NULL values and want to make them NOT NULL again. You would then execute these generated commands in the same way as before.