SELECT col.attname as column_name, ( SELECT pg_catalog.pg_get_expr(def.adbin, def.adrelid) FROM pg_catalog.pg_attrdef def WHERE def.adrelid = col.attrelid AND def.adnum = col.attnum AND col.atthasdef ) as column_default, col.attnum as ordinal_position, CASE WHEN typ.typcategory ='E' THEN 'enum' WHEN typ.typcategory='C' THEN 'composite' ELSE pg_catalog.format_type(col.atttypid, col.atttypmod) END AS type_format, ( SELECT pg_get_serial_sequence(format('%I.%I',tabsch.nspname,tab.relname), col.attname) IS NOT NULL FROM pg_catalog.pg_class tab INNER JOIN pg_catalog.pg_namespace tabsch ON tab.relnamespace=tabsch.oid WHERE tab.oid=col.attrelid ) as col_serial, typ.typcategory as type_category, CASE WHEN typ.typcategory='E' THEN ( SELECT string_agg(quote_literal(enumlabel),',') FROM pg_catalog.pg_enum enm WHERE enm.enumtypid=typ.oid ) WHEN typ.typcategory='C' THEN ( SELECT string_agg( format('%I %s', attname, pg_catalog.format_type(atttypid, atttypmod) ) , ',' ) FROM pg_catalog.pg_attribute WHERE attrelid=format( '%I.%I', sch.nspname, typ.typname)::regclass ) END AS typ_elements, col.attnotnull as not_null FROM pg_catalog.pg_attribute col INNER JOIN pg_catalog.pg_type typ ON col.atttypid=typ.oid INNER JOIN pg_catalog.pg_namespace sch ON typ.typnamespace=sch.oid WHERE col.attrelid = 'foo.bar'::regclass --this is used to filter the table's name AND NOT col.attisdropped AND col.attnum>0 ORDER BY col.attnum ;