WITH unique_columns AS (SELECT
n.nspname AS table_schema,
c2.relname AS table_name,
a.attname AS column_name
FROM
pg_catalog.pg_class AS c INNER JOIN pg_catalog.pg_index AS i ON i.indexrelid = c.oid
INNER JOIN pg_catalog.pg_class AS c2 ON i.indrelid = c2.oid
INNER JOIN pg_catalog.pg_namespace AS n ON c.relnamespace = n.oid
INNER JOIN pg_catalog.pg_authid AS u ON n.nspowner = u.oid
INNER JOIN pg_catalog.pg_attribute AS a ON a.attrelid = c.oid
WHERE c.relkind = 'i'
AND i.indisunique=TRUE
AND a.attnum>=1
AND a.attisdropped = FALSE
AND (n.nspname = 'public'
OR u.rolname <> 'postgres')),
fk as (select
(select nspname from pg_namespace where oid=c.relnamespace) as target_schema,
c.relname as target_table,
c.oid as target_table_oid,
o.conkey AS target_col
from pg_constraint o inner join pg_class c on c.oid = o.conrelid
where o.contype = 'f'),
fk_unnest as (select target_schema, target_table, target_table_oid, target_col, target_col_num, ordin
from fk, unnest(fk. target_col) with ordinality as f(target_col_num, ordin)),
fk_with_names as (select target_schema, target_table, a_target.attname as target_col
from fk_unnest fk inner join pg_attribute a_target on fk.target_col_num = a_target.attnum and fk.target_table_oid = a_target.attrelid and a_target.attisdropped = false)
SELECT A.table_schema, A.table_name , A.column_name, CASE WHEN A.data_type ILIKE 'character%' AND A.character_maximum_length IS NOT NULL THEN A.data_type || '(' || A.character_maximum_length::text || ')'
WHEN A.data_type ILIKE 'timestamp%' AND A.datetime_precision IS NOT NULL THEN A.data_type || '(' || A.datetime_precision || ')'
WHEN A.data_type ILIKE 'numeric%' AND A.numeric_precision IS NOT NULL THEN A.data_type || '(' || A.numeric_precision::text || ',' ||coalesce(A.numeric_scale,0)::text || ')'
WHEN A.data_type ILIKE 'interval%' AND A.interval_type IS NOT NULL THEN A.data_type || '(' || A.interval_type::text || ')'
WHEN A.data_type='USER-DEFINED' THEN A.udt_schema || '.' || A.udt_name
ELSE A.data_type END AS data_type
FROM information_schema.columns A INNER JOIN information_schema.tables T USING (table_schema, table_name)
INNER JOIN information_schema.schemata S ON A.table_schema=S.schema_name
WHERE is_nullable='YES'
AND T.table_type='BASE TABLE'
AND (A.table_schema = 'public'
OR S.schema_owner<>'postgres')
AND (table_schema, table_name, column_name) IN (SELECT table_schema, table_name, column_name
FROM unique_columns)
AND NOT EXISTS (SELECT *
FROM fk_with_names AS fwn
WHERE A.table_schema=fwn.target_schema
AND A.table_name=fwn.target_table
AND A.column_name=fwn.target_col)
ORDER BY table_schema, table_name, ordinal_position;