How to get the list of all constraints, their tables and their columns in postgres? - postgresql

I want to get the list of all constraints, their tables and their columns, something like
constraint | table | columns
------------------------------|-------|---------------
table1_colum1_colum2_key table1 {colum1, colum2}
How can this be done?

The constraints can be queried via pg_constraint. Tables are included in pg_class and columns in pg_attributes. Schemas are in pg_namespace.
Something like the following may work for you.
SELECT con.conname "constraint",
concat(nsp.nspname, '.', rel.relname) "table",
(SELECT array_agg(att.attname)
FROM pg_attribute att
INNER JOIN unnest(con.conkey) unnest(conkey)
ON unnest.conkey = att.attnum
WHERE att.attrelid = con.conrelid) "columns"
FROM pg_constraint con
INNER JOIN pg_class rel
ON rel.oid = con.conrelid
INNER JOIN pg_namespace nsp
ON nsp.oid = rel.relnamespace;

Related

How to list all constraints of all tables in PostgreSQL?

How to list all constraints of all tables in PostgreSQL?
I need to search the unique constraint created a long time ago, the database has so many (600) tables. It's hard to find. Is there any query to list all constraints of all tables
You must refer to pg_constraint.
If you need to list just the unique constraint filter on contype, like this:
select * from pg_catalog.pg_constraint pc
where contype = 'u'
Documentation here: https://www.postgresql.org/docs/current/catalog-pg-constraint.html
The below query will List all the constraints of a table in the PostgreSQL database.
You can try below:-
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 with the name of your table & with the name of your schema.
It can be viewed in PSQL as using below:-
d+ <SCHEMA_NAME.TABLE_NAME>

Get all the column names having a Foreign Key contraint

I am using the PostgreSQL. I want to write a query that returns all the column names having foreign key constraint and also the name of the table these columns they refer to.
As far as I can see, the information_schema views don't give you the column names, so you'll have to use the catalog:
SELECT c.conrelid::regclass AS source_table,
a.attname AS column_name,
k.n AS position,
c.confrelid::regclass AS referenced_table
FROM pg_constraint AS c
CROSS JOIN LATERAL unnest(c.conkey) WITH ORDINALITY AS k(attnum, n)
JOIN pg_attribute AS a
ON k.attnum = a.attnum AND c.conrelid = a.attrelid
WHERE c.contype = 'f'
ORDER BY c.conrelid::regclass::text, k.n;
To get the data for only a specific table, add the following to the WHERE condition:
AND c.conrelid = 'mytable'::regclass

How to get column name from pg_constraint

I need to get a list of constraints from db and match them with columns they are related to
For this task I'm going to use pg_constraint. Here is the query that I use
select conrelid::regclass AS table_from, conname, pg_get_constraintdef(c.oid)
from pg_constraint c
join pg_namespace n ON n.oid = c.connamespace
where conrelid::regclass::text = 'test' order by contype;
As you can see I'm interested in constraints for table called test
Here is the output
table_from | conname | pg_get_constraintdef
------------+----------------+----------------------
test | test_age_check | CHECK ((age > 0))
But I want to get a column name for this constraint using query above (In this case column is age). According to doc Column constraints are not treated specially. But maybe there are some ways I can use to retrieve column name from pg_constraint ?
pg_constrint.conkey holds an array of the columns ordinals in the table. You can use them to join pg_attribute. Here the ordinal is in the column attnum.
SELECT c.conrelid::regclass AS table_from,
c.conname,
pg_get_constraintdef(c.oid),
a.attname
FROM pg_constraint c
INNER JOIN pg_namespace n
ON n.oid = c.connamespace
CROSS JOIN LATERAL unnest(c.conkey) ak(k)
INNER JOIN pg_attribute a
ON a.attrelid = c.conrelid
AND a.attnum = ak.k
WHERE c.conrelid::regclass::text = 'test'
ORDER BY c.contype;

I need to know the list of tables on which there are locks currently

select
A.table_id,
last_update,
last_commit,
lock_owner_pid,
lock_status,
B.table
from stv_locks as A left outer join svv_table_info as B on A.table_id = B.table_id
order by last_update asc
I used the query above, but am getting null in a name for some table_ids. what are these?
select distinct(id) table_id
,trim(datname) db_name
,trim(nspname) schema_name
,trim(relname) table_name
from stv_locks
join stv_tbl_perm on stv_locks.table_id = stv_tbl_perm.id
join pg_class on pg_class.oid = stv_tbl_perm.id
join pg_namespace on pg_namespace.oid = relnamespace
join pg_database on pg_database.oid = stv_tbl_perm.db_id;
This should work. You can add other columns based on your use case!
If I’ve made a bad assumption please comment and I’ll refocus my answer.

List columns with indexes in Amazon Redshift

I need to query Redshift metadata to get a list of table columns that includes information whether the column is part of primary key or not.
There is a post already List columns with indexes in PostgreSQL that has an answer for PostgreSQL, however unfortunately, it fails on Redshift with "ERROR: 42809: op ANY/ALL (array) requires array on right side"
I figured out how to do it with the help of this https://bitbucket.org/zzzeek/sqlalchemy/pull-request/6/sqlalchemy-to-support-postgresql-80/diff
SELECT attname column_name, attnotnull,
format_type(atttypid, atttypmod) as column_type, atttypmod,
i.indisprimary as primary_key,
col_description(attrelid, attnum) as description
FROM pg_attribute c
LEFT OUTER JOIN pg_index i
ON c.attrelid = i.indrelid AND i.indisprimary AND
c.attnum = ANY(string_to_array(textin(int2vectorout(i.indkey)), ' '))
where c.attnum > 0 AND NOT c.attisdropped AND c.attrelid = :tableOid
order by attnum
The following worked for me:
SELECT n.nspname as schema_name,
t.relname as table_name,
i.relname as index_name,
c.contype as index_type,
a.attname as column_name,
a.attnum AS column_position
FROM pg_class t
INNER JOIN pg_index AS ix ON t.oid = ix.indrelid
INNER JOIN pg_constraint AS c ON ix.indrelid = c.conrelid
INNER JOIN pg_class AS i ON i.oid = ix.indexrelid
INNER JOIN pg_attribute AS a ON a.attrelid = t.oid
AND a.attnum= ANY(string_to_array(textin(int2vectorout(ix.indkey)),' ')::int[])
INNER JOIN pg_namespace AS n ON n.oid = t.relnamespace;
You can leverage the table DDL view AWS published a few months ago (https://github.com/awslabs/amazon-redshift-utils/blob/master/src/AdminViews/v_generate_tbl_ddl.sql) by picking out the constraint component and parsing out the key columns:
select schemaname,tablename, substring(ddl,charindex('(',ddl)+1, charindex(')',ddl)-1-charindex('(',ddl))
from
(
SELECT
n.nspname AS schemaname
,c.relname AS tablename
,200000000 + CAST(con.oid AS INT) AS seq
,'\t,' + pg_get_constraintdef(con.oid) AS ddl
FROM
pg_constraint AS con
INNER JOIN pg_class AS c
ON c.relnamespace = con.connamespace
AND c.relfilenode = con.conrelid
INNER JOIN pg_namespace AS n
ON n.oid = c.relnamespace
WHERE c.relkind = 'r'
ORDER BY seq
)
Note that this query also gives you foreign key columns. It's easy enough to filter those out by appending the query with
where ddl like '%PRIMARY KEY%'
Use below query:
select * from pg_table_def where tablename = 'mytablename'
This will give you all columns for table along with their data type , encoding and if it has sort key or dist key.