161

How to list all constraints (Primary key, check, unique mutual exclusive, ..) of a table in PostgreSQL?

Thirumal
  • 2,398
  • 3
  • 13
  • 24

4 Answers4

187

Constraints can be retrieved via pg_catalog.pg_constraint.

SELECT con.*
       FROM pg_catalog.pg_constraint con
            INNER JOIN pg_catalog.pg_class rel
                       ON rel.oid = con.conrelid
            INNER JOIN pg_catalog.pg_namespace nsp
                       ON nsp.oid = connamespace
       WHERE nsp.nspname = '<schema name>'
             AND rel.relname = '<table name>';

Replace <schema name> with the name of your schema and <table name> with the name of your table.

sticky bit
  • 4,834
  • 2
  • 13
  • 19
  • 9
    Notice that pg_catalog.pg_constraint does not contain NOT NULL constraints. – Luís de Sousa Jul 24 '19 at 08:30
  • @sticky bit, is there anyway to drop all the constraints identified in a table? using single query? How can I pass this list of constraints as input to `ALTER TABLE DROP CONSTRAINT CASCADE;?
    – The Great Jul 16 '21 at 10:47
  • What is schema name? – Yoan Arnaudov Dec 22 '21 at 07:41
  • @nacholibre: The name of the schema of the table. – sticky bit Dec 22 '21 at 14:34
  • @TheGreat Old comment, I know, but this is a hack for lack of a better one: select concat('alter table ', table_schema, '.', table_name, ' drop constraint ', constraint_name, ';') from information_schema.table_constraints where constraint_name [pattern match]; Just set the query part and copy the result into psql. – Rob Skelly Feb 01 '22 at 00:13
  • If someone is looking to get not null constraints for a table can use this. SELECT table_schema, table_name, column_name FROM information_schema.columns WHERE is_nullable = 'NO' and table_name = 'your_table_name'; – v1shva Jul 13 '22 at 01:51
51

In the psql command line this information is in the table sheet, obtained with the \d+ command. d+ also informs on the NOT NULL constraints, something that is not present in the pg_catalog.pg_constraint table. An example:

# \d+ observations.stream   
                                                  Table "observations.stream"
 Column |       Type        | Collation | Nullable | Default | Storage  | Stats target |                 Description                 
--------+-------------------+-----------+----------+---------+----------+--------------+---------------------------------------------
 id     | integer           |           | not null |         | plain    |              | 
 name   | character varying |           | not null |         | extended |              | This should be a table in the import schema
 min_id | integer           |           | not null |         | plain    |              | 
 about  | character varying |           | not null |         | extended |              | 
Indexes:
    "stream_pkey" PRIMARY KEY, btree (id)
    "stream_name_key" UNIQUE CONSTRAINT, btree (name)
Check constraints:
    "stream_id_check" CHECK (id > 0)
Referenced by:
    TABLE "profile" CONSTRAINT "profile_id_stream_fkey" FOREIGN KEY (id_stream) REFERENCES stream(id)

The caveat here is that you do not get the names of all the constraints this way.

Luís de Sousa
  • 634
  • 6
  • 11
6

Here is PostgreSQL specific answer. It will retrieve all columns and their relationship as well:

select *FROM (
from (
    select
        pgc.contype as constraint_type,
        ccu.table_schema as table_schema,
        kcu.table_name as table_name,
        case when (pgc.contype = 'f') then kcu.column_name else ccu.column_name end as column_name, 
        case when (pgc.contype = 'f') then ccu.table_name else (null) end as reference_table,
        case when (pgc.contype = 'f') then ccu.column_name else (null) end as reference_col,
        case when (pgc.contype = 'p') then 'yes' else 'no' end as auto_inc,
        case when (pgc.contype = 'p') then 'no' else 'yes' end as is_nullable,
        'integer' as data_type,
        '0' as numeric_scale,
        '32' as numeric_precision
    from
        pg_constraint as pgc
        join pg_namespace nsp on nsp.oid = pgc.connamespace
        join pg_class cls on pgc.conrelid = cls.oid
        join information_schema.key_column_usage kcu on kcu.constraint_name = pgc.conname
        left join information_schema.constraint_column_usage ccu on pgc.conname = ccu.constraint_name 
        and nsp.nspname = ccu.constraint_schema
     union
        select 
            null as constraint_type ,
            table_schema,
            table_name,
            column_name, 
            null as refrence_table, 
            null as refrence_col, 
            'no' as auto_inc,
            is_nullable,
            data_type,
            numeric_scale,
            numeric_precision
        from information_schema.columns cols 
        where 
            table_schema = 'public'
            and concat(table_name, column_name) not in(
                select concat(kcu.table_name, kcu.column_name)
                from
                pg_constraint as pgc
                join pg_namespace nsp on nsp.oid = pgc.connamespace
                join pg_class cls on pgc.conrelid = cls.oid
                join information_schema.key_column_usage kcu on kcu.constraint_name = pgc.conname
                left join information_schema.constraint_column_usage ccu on pgc.conname = ccu.constraint_name 
                and nsp.nspname = ccu.constraint_schema
            )
    ) as foo
order by table_name asc, column_name

John K. N.
  • 17,649
  • 12
  • 51
  • 110
Mohsin Ejaz
  • 161
  • 1
  • 2
  • The where clause table_name not in (...) does not work correctly because different tables can have same fields, this leads to less fields. Also 'integer' as data_type is not always true, an example is an unique email field that is varchar. – UselesssCat Jan 03 '22 at 15:23
2

The previous answer showed unreadable checks column that was compiled or something

This query results are readable in all directions

select tc.table_schema,
  tc.table_name,
  string_agg(col.column_name, ', ') as columns,
  tc.constraint_name,
  cc.check_clause
from information_schema.table_constraints tc
join information_schema.check_constraints cc
  on tc.constraint_schema = cc.constraint_schema
  and tc.constraint_name = cc.constraint_name
join pg_namespace nsp on nsp.nspname = cc.constraint_schema
join pg_constraint pgc on pgc.conname = cc.constraint_name
  and pgc.connamespace = nsp.oid
  and pgc.contype = 'c'
join information_schema.columns col
  on col.table_schema = tc.table_schema
  and col.table_name = tc.table_name
  and col.ordinal_position = ANY(pgc.conkey)
where tc.constraint_schema not in('pg_catalog', 'information_schema')
group by tc.table_schema,
  tc.table_name,
  tc.constraint_name,
  cc.check_clause
order by tc.table_schema,
  tc.table_name;
Korayem
  • 121
  • 3