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
Related
I want to write a query to list the check constraints in a database along with its constraint definition.
I am not able to find a column to find the check constraint definition just like the search condition column in oracle all_constraints table.
Is there a PG alternate for this?
The catalog pg_constraint stores check, primary key, unique, foreign key, and exclusion constraints on tables and contype column saves data about the type of the constraint i,e
c = check constraint
f = foreign key constraint
p = primary key constraint
u = unique constraint
t = constraint trigger
x = exclusion constraint
select pgc.conname as constraint_name,
ccu.table_schema as table_schema,
ccu.table_name,
ccu.column_name,
pg_get_constraintdef(pgc.oid)
from pg_constraint pgc
join pg_namespace nsp on nsp.oid = pgc.connamespace
join pg_class cls on pgc.conrelid = cls.oid
left join information_schema.constraint_column_usage ccu
on pgc.conname = ccu.constraint_name
and nsp.nspname = ccu.constraint_schema
where contype ='c'
order by pgc.conname;
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 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;
I have lots of tables with lots of foreign keys and about all of them are UPDATE NO ACTION and DELETE NO ACTION.
Is it possible to dynamically update all this foreign keys to CASCADE instead of NO ACTION or RESTRICT?
For example:
ALTER TABLE * ALTER FOREIGN KEY * SET ON UPDATE CASCADE ON DELETE CASCADE;
Yours,
Diogo
No, this is not possible.
You will need to drop and re-create all constraints as a foreign key constraint cannot be altered like that.
The following statement will generate the necessary alter table statements to drop and re-create the foreign keys:
select 'alter table '||pgn.nspname||'.'||tbl.relname||' drop constraint '||cons.conname||';'
from pg_constraint cons
join pg_class tbl on cons.confrelid = tbl.oid
join pg_namespace pgn on pgn.oid = tbl.relnamespace
where contype = 'f'
union all
select 'alter table '||pgn.nspname||'.'||tbl.relname||' add constraint '||cons.conname||' '||pg_get_constraintdef(cons.oid, true)||' ON UPDATE CASCADE ON DELETE CASCADE;'
from pg_constraint cons
join pg_class tbl on cons.confrelid = tbl.oid
join pg_namespace pgn on pgn.oid = tbl.relnamespace
where contype = 'f'
Save the output of this statement to a file and run it.
Make sure you validate the generated statements before running them!
I would use the following code to generate the necessary alter table SQL statements to drop and re-create the foreign keys (in order):
select 'ALTER TABLE '||pgn.nspname||'.'||tbl.relname||' DROP CONSTRAINT '||cons.conname||';' as sqlstr
from pg_constraint cons
join pg_class tbl on cons.conrelid = tbl.oid
join pg_namespace pgn on pgn.oid = tbl.relnamespace
where contype = 'f'
union
select 'ALTER TABLE '||pgn.nspname||'.'||tbl.relname||' ADD CONSTRAINT '||cons.conname||' FOREIGN KEY ('||(select attname from pg_attribute where attrelid=cons.conrelid and attnum = ANY(cons.conkey))||') REFERENCES '||tblf.relname||' ('||(select attname from pg_attribute where attrelid=cons.confrelid and attnum = ANY(cons.confkey))||') ON UPDATE CASCADE ON DELETE CASCADE;' as sqlstr
from pg_constraint cons
join pg_class tbl on cons.conrelid = tbl.oid
join pg_namespace pgn on pgn.oid = tbl.relnamespace
join pg_class tblf on cons.confrelid = tblf.oid
where contype = 'f'
ORDER BY sqlstr desc
I have two tables (tbl and tbl_new) that both use the same sequence (tbl_id_seq). I'd like to drop one of those tables. On tbl, I've removed the modifier "not null default nextval('tbl_id_seq'::regclass)" but that modifier remains on tbl_new. I'm getting the following error:
ERROR: cannot drop table tbl because other objects depend on it
DETAIL: default for table tbl_new column id depends on sequence tbl_id_seq
After reviewing http://www.postgresql.org/docs/9.1/static/sql-droptable.html
It looks like there is only CASCADE and RESTRICT as options.
You need to decouple the sequence and the table it "belongs" to:
ALTER SEQUENCE "tbl_id_seq" OWNED BY NONE;
I suppose it was created automatically (and "bound") by defining the tbl_id field of tbl as SERIAL.
To find sequences and all tables that depend on them via column default:
SELECT sn.nspname || '.' || s.relname AS seq
,tn.nspname || '.' || t.relname AS tbl
FROM pg_class s
JOIN pg_namespace sn ON sn.oid = s.relnamespace
LEFT JOIN pg_depend d ON d.refobjid = s.oid AND d.deptype <> 'i'
LEFT JOIN pg_attrdef ad ON ad.oid = d.objid
LEFT JOIN pg_class t ON t.oid = ad.adrelid
LEFT JOIN pg_namespace tn ON tn.oid = t.relnamespace
WHERE s.relkind = 'S'
AND s.relname ~~ '%part_of_seq_name%' -- enter search term here
ORDER BY 1,2;
Now with LEFT JOIN to show "free-standing" sequences as well.
You can then use the method #Milen posted to make the sequence "free-standing".
I posted a related answer a few days ago.