Find dependent objects for a table or view
The suggested solution didn't work for me with postgresql 9.1.4
this worked:
SELECT dependent_ns.nspname as dependent_schema
, dependent_view.relname as dependent_view
, source_ns.nspname as source_schema
, source_table.relname as source_table
, pg_attribute.attname as column_name
FROM pg_depend
JOIN pg_rewrite ON pg_depend.objid = pg_rewrite.oid
JOIN pg_class as dependent_view ON pg_rewrite.ev_class = dependent_view.oid
JOIN pg_class as source_table ON pg_depend.refobjid = source_table.oid
JOIN pg_attribute ON pg_depend.refobjid = pg_attribute.attrelid
AND pg_depend.refobjsubid = pg_attribute.attnum
JOIN pg_namespace dependent_ns ON dependent_ns.oid = dependent_view.relnamespace
JOIN pg_namespace source_ns ON source_ns.oid = source_table.relnamespace
WHERE
source_ns.nspname = 'my_schema'
AND source_table.relname = 'my_table'
AND pg_attribute.attnum > 0
AND pg_attribute.attname = 'my_column'
ORDER BY 1,2;
Include nested views in the query as follows:
WITH RECURSIVE view_deps AS (
SELECT DISTINCT dependent_ns.nspname as dependent_schema
, dependent_view.relname as dependent_view
, source_ns.nspname as source_schema
, source_table.relname as source_table
FROM pg_depend
JOIN pg_rewrite ON pg_depend.objid = pg_rewrite.oid
JOIN pg_class as dependent_view ON pg_rewrite.ev_class = dependent_view.oid
JOIN pg_class as source_table ON pg_depend.refobjid = source_table.oid
JOIN pg_namespace dependent_ns ON dependent_ns.oid = dependent_view.relnamespace
JOIN pg_namespace source_ns ON source_ns.oid = source_table.relnamespace
WHERE NOT (dependent_ns.nspname = source_ns.nspname AND dependent_view.relname = source_table.relname)
UNION
SELECT DISTINCT dependent_ns.nspname as dependent_schema
, dependent_view.relname as dependent_view
, source_ns.nspname as source_schema
, source_table.relname as source_table
FROM pg_depend
JOIN pg_rewrite ON pg_depend.objid = pg_rewrite.oid
JOIN pg_class as dependent_view ON pg_rewrite.ev_class = dependent_view.oid
JOIN pg_class as source_table ON pg_depend.refobjid = source_table.oid
JOIN pg_namespace dependent_ns ON dependent_ns.oid = dependent_view.relnamespace
JOIN pg_namespace source_ns ON source_ns.oid = source_table.relnamespace
INNER JOIN view_deps vd
ON vd.dependent_schema = source_ns.nspname
AND vd.dependent_view = source_table.relname
AND NOT (dependent_ns.nspname = vd.dependent_schema AND dependent_view.relname = vd.dependent_view)
)
SELECT *
FROM view_deps
ORDER BY source_schema, source_table;
If you care about specific table attributes add this to the top portion of the recursive CTE:
JOIN pg_attribute ON pg_depend.refobjid = pg_attribute.attrelid
AND pg_depend.refobjsubid = pg_attribute.attnum
...
WHERE
source_ns.nspname = 'my_schema'
AND source_table.relname = 'my_table'
AND pg_attribute.attnum > 0
AND pg_attribute.attname = 'my_column'
The easy way is:
BEGIN;
DROP TABLE tablename CASCADE;
DROP VIEW viewname CASCADE;
ROLLBACK;
For PostgreSQL 9.3 onward use the following view and functions to show any user object dependency. I also updated https://wiki.postgresql.org/wiki/Pg_depend_display.
/**** Usage Examples ****
-- Examine the entire object hierarchy
SELECT report.dependency_tree('');
-- Dependencies for any relations with names containing match (in regular expression)
SELECT report.dependency_tree('match');
-- Dependencies for relations person & address
SELECT report.dependency_tree('{person,address}'::text[]);
-- Dependencies for function slice
SELECT report.dependency_tree(ARRAY['slice'::regproc]);
-- Dependencies for type hstore
SELECT report.dependency_tree(ARRAY['hstore'::regtype]);
-- Dependencies for triggers by the name updated
SELECT report.dependency_tree(ARRAY(
SELECT oid FROM pg_trigger WHERE tgname ~ 'updated'
));
-- Dependencies for foreign key constraint names starting with product
SELECT report.dependency_tree(ARRAY(
SELECT oid FROM pg_constraint
WHERE conname ~ '^product.*_fk'
));
*/
DROP VIEW IF EXISTS report.dependency;
CREATE OR REPLACE VIEW report.dependency AS
WITH RECURSIVE preference AS (
SELECT 10 AS max_depth
, 16384 AS min_oid -- user objects only
, '^(londiste|pgq|pg_toast)'::text AS schema_exclusion
, '^pg_(conversion|language|ts_(dict|template))'::text AS class_exclusion
, '{"SCHEMA":"00", "TABLE":"01", "TABLE CONSTRAINT":"02", "DEFAULT VALUE":"03",
"INDEX":"05", "SEQUENCE":"06", "TRIGGER":"07", "FUNCTION":"08",
"VIEW":"10", "MATERIALIZED VIEW":"11", "FOREIGN TABLE":"12"}'::json AS type_sort_orders
)
, dependency_pair AS (
SELECT objid
, array_agg(objsubid ORDER BY objsubid) AS objsubids
, upper(obj.type) AS object_type
, coalesce(obj.schema, substring(obj.identity, E'(\\w+?)\\.'), '') AS object_schema
, obj.name AS object_name
, obj.identity AS object_identity
, refobjid
, array_agg(refobjsubid ORDER BY refobjsubid) AS refobjsubids
, upper(refobj.type) AS refobj_type
, coalesce(CASE WHEN refobj.type='schema' THEN refobj.identity
ELSE refobj.schema END
, substring(refobj.identity, E'(\\w+?)\\.'), '') AS refobj_schema
, refobj.name AS refobj_name
, refobj.identity AS refobj_identity
, CASE deptype
WHEN 'n' THEN 'normal'
WHEN 'a' THEN 'automatic'
WHEN 'i' THEN 'internal'
WHEN 'e' THEN 'extension'
WHEN 'p' THEN 'pinned'
END AS dependency_type
FROM pg_depend dep
, LATERAL pg_identify_object(classid, objid, 0) AS obj
, LATERAL pg_identify_object(refclassid, refobjid, 0) AS refobj
, preference
WHERE deptype = ANY('{n,a}')
AND objid >= preference.min_oid
AND (refobjid >= preference.min_oid OR refobjid = 2200) -- need public schema as root node
AND coalesce(obj.schema, substring(obj.identity, E'(\\w+?)\\.'), '') !~ preference.schema_exclusion
AND coalesce(CASE WHEN refobj.type='schema' THEN refobj.identity
ELSE refobj.schema END
, substring(refobj.identity, E'(\\w+?)\\.'), '') !~ preference.schema_exclusion
GROUP BY objid, obj.type, obj.schema, obj.name, obj.identity
, refobjid, refobj.type, refobj.schema, refobj.name, refobj.identity, deptype
)
, dependency_hierarchy AS (
SELECT DISTINCT
0 AS level,
refobjid AS objid,
refobj_type AS object_type,
refobj_identity AS object_identity,
--refobjsubids AS objsubids,
NULL::text AS dependency_type,
ARRAY[refobjid] AS dependency_chain,
ARRAY[concat(preference.type_sort_orders->>refobj_type,refobj_type,':',refobj_identity)] AS dependency_sort_chain
FROM dependency_pair root
, preference
WHERE NOT EXISTS
(SELECT 'x' FROM dependency_pair branch WHERE branch.objid = root.refobjid)
AND refobj_schema !~ preference.schema_exclusion
UNION ALL
SELECT
level + 1 AS level,
child.objid,
child.object_type,
child.object_identity,
--child.objsubids,
child.dependency_type,
parent.dependency_chain || child.objid,
parent.dependency_sort_chain || concat(preference.type_sort_orders->>child.object_type,child.object_type,':',child.object_identity)
FROM dependency_pair child
JOIN dependency_hierarchy parent ON (parent.objid = child.refobjid)
, preference
WHERE level < preference.max_depth
AND child.object_schema !~ preference.schema_exclusion
AND child.refobj_schema !~ preference.schema_exclusion
AND NOT (child.objid = ANY(parent.dependency_chain)) -- prevent circular referencing
)
SELECT * FROM dependency_hierarchy
ORDER BY dependency_chain ;
-- Procedure to report depedency tree using regexp search pattern (relation-only)
CREATE OR REPLACE FUNCTION report.dependency_tree(search_pattern text)
RETURNS TABLE(dependency_tree text)
SECURITY DEFINER LANGUAGE SQL
AS $function$
WITH target AS (
SELECT objid, dependency_chain
FROM report.dependency
WHERE object_identity ~ search_pattern
)
, list AS (
SELECT
format('%*s%s %s', -4*level
, CASE WHEN object_identity ~ search_pattern THEN '*' END
, object_type, object_identity
) AS dependency_tree
, dependency_sort_chain
FROM target
JOIN report.dependency report
ON report.objid = ANY(target.dependency_chain) -- root-bound chain
OR target.objid = ANY(report.dependency_chain) -- leaf-bound chain
WHERE length(search_pattern) > 0
-- Do NOT waste search time on blank/null search_pattern.
UNION
-- Query the entire dependencies instead.
SELECT
format('%*s%s %s', 4*level, '', object_type, object_identity) AS depedency_tree
, dependency_sort_chain
FROM report.dependency
WHERE length(coalesce(search_pattern,'')) = 0
)
SELECT dependency_tree FROM list
ORDER BY dependency_sort_chain;
$function$ ;
-- Procedure to report depedency tree by specific relation name(s) (in text array)
CREATE OR REPLACE FUNCTION report.dependency_tree(object_names text[])
RETURNS TABLE(dependency_tree text)
SECURITY DEFINER LANGUAGE SQL
AS $function$
WITH target AS (
SELECT objid, dependency_chain
FROM report.dependency
JOIN unnest(object_names) AS target(objname) ON objid = objname::regclass
)
, list AS (
SELECT DISTINCT
format('%*s%s %s', -4*level
, CASE WHEN object_identity = ANY(object_names) THEN '*' END
, object_type, object_identity
) AS dependency_tree
, dependency_sort_chain
FROM target
JOIN report.dependency report
ON report.objid = ANY(target.dependency_chain) -- root-bound chain
OR target.objid = ANY(report.dependency_chain) -- leaf-bound chain
)
SELECT dependency_tree FROM list
ORDER BY dependency_sort_chain;
$function$ ;
-- Procedure to report depedency tree by oid
CREATE OR REPLACE FUNCTION report.dependency_tree(object_ids oid[])
RETURNS TABLE(dependency_tree text)
SECURITY DEFINER LANGUAGE SQL
AS $function$
WITH target AS (
SELECT objid, dependency_chain
FROM report.dependency
JOIN unnest(object_ids) AS target(objid) USING (objid)
)
, list AS (
SELECT DISTINCT
format('%*s%s %s', -4*level
, CASE WHEN report.objid = ANY(object_ids) THEN '*' END
, object_type, object_identity
) AS dependency_tree
, dependency_sort_chain
FROM target
JOIN report.dependency report
ON report.objid = ANY(target.dependency_chain) -- root-bound chain
OR target.objid = ANY(report.dependency_chain) -- leaf-bound chain
)
SELECT dependency_tree FROM list
ORDER BY dependency_sort_chain;
$function$ ;