查找表或视图的依赖对象

发布于 2024-10-08 03:25:51 字数 815 浏览 2 评论 0原文

背景

在 PostgreSQL 中删除(或替换)对象时,如果存在依赖关系,则删除将会失败(不指定 CASCADE)。

问题

数据库返回的错误消息未列出依赖对象。

解决方案示例

该查询可能类似于:

SELECT * FROM information_schema i, pg_depend pd WHERE
  i.object_id = pd.object_id AND
  i.object_type = 'TABLE' AND
  i.object_schema = 'public' AND
  i.object_name = 'table_with_dependents';

缺少 objid

相关

问题

如何按名称和类型生成依赖对象的列表?

Background

When dropping (or replacing) objects in PostgreSQL, if there are dependencies, the drop will fail (without specifying CASCADE).

Problem

The error message returned by the database does not list the dependent objects.

Example Solution

The query might look something like:

SELECT * FROM information_schema i, pg_depend pd WHERE
  i.object_id = pd.object_id AND
  i.object_type = 'TABLE' AND
  i.object_schema = 'public' AND
  i.object_name = 'table_with_dependents';

The objid is missing.

Related

Question

How do you generate a list of dependent objects by name and type?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(6

乞讨 2024-10-15 03:25:51

建议的解决方案对我来说不起作用,但 postgresql 9.1.4

有效:

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;

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;
赠意 2024-10-15 03:25:51

简单的方法是:

BEGIN;
DROP TABLE tablename CASCADE;
DROP VIEW viewname CASCADE;
ROLLBACK;

The easy way is:

BEGIN;
DROP TABLE tablename CASCADE;
DROP VIEW viewname CASCADE;
ROLLBACK;
梦里南柯 2024-10-15 03:25:51

在查询中包含嵌套视图,如下所示:

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;

如果您关心特定表属性,请将其添加到递归 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'

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'
尐籹人 2024-10-15 03:25:51

对于 PostgreSQL 9.3 及更高版本,请使用以下视图和函数来显示任何用户对象依赖性。我还更新了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$ ;

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$ ;
是你 2024-10-15 03:25:51

根据 Kong Man 的答案,下面的 CTE 返回与给定表/视图交互的所有表和视图。在 PostgreSQL 15.3 中测试。

用法示例,在 CTE 末尾过滤特定架构和表:

SELECT *
FROM final
WHERE CAST(dependency_sort_chain as VARCHAR) like '%manual.dim_command%'
        AND schema_and_object <> 'manual.dim_command'
ORDER BY schema_and_object;

返回引用它的所有表和视图:
输入图片此处描述

-- Credit to Kong Man. Source: https://stackoverflow.com/a/28290575/5834512
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 AS 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
), 

aliased_and_filtered as (

    SELECT level
        , objid as object_id
        , object_type
        , object_identity
        , dependency_type
        , dependency_chain
        , dependency_sort_chain
    FROM dependency_hierarchy
    WHERE object_type IN ('TABLE CONSTRAINT','RULE')

), 

text_search as (
    SELECT level
        , object_id
        , object_type
        , CASE WHEN object_identity like '% on %'
            THEN SUBSTR(object_identity, position(' on ' in object_identity)+ 4)
            END AS schema_and_object
        , object_identity
        , dependency_type
        , dependency_chain
        , dependency_sort_chain
    FROM aliased_and_filtered
), 

final as (

    SELECT *
    FROM text_search
)

SELECT *
FROM final
ORDER BY schema_and_object;

Building off of Kong Man's answer, the below CTE returns all the tables and views that interact with a given table/view. Tested in PostgreSQL 15.3.

Example usage, filtering for a specific schema and table at the end of the CTE:

SELECT *
FROM final
WHERE CAST(dependency_sort_chain as VARCHAR) like '%manual.dim_command%'
        AND schema_and_object <> 'manual.dim_command'
ORDER BY schema_and_object;

Returns all the tables and views that reference it:
enter image description here

-- Credit to Kong Man. Source: https://stackoverflow.com/a/28290575/5834512
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 AS 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
), 

aliased_and_filtered as (

    SELECT level
        , objid as object_id
        , object_type
        , object_identity
        , dependency_type
        , dependency_chain
        , dependency_sort_chain
    FROM dependency_hierarchy
    WHERE object_type IN ('TABLE CONSTRAINT','RULE')

), 

text_search as (
    SELECT level
        , object_id
        , object_type
        , CASE WHEN object_identity like '% on %'
            THEN SUBSTR(object_identity, position(' on ' in object_identity)+ 4)
            END AS schema_and_object
        , object_identity
        , dependency_type
        , dependency_chain
        , dependency_sort_chain
    FROM aliased_and_filtered
), 

final as (

    SELECT *
    FROM text_search
)

SELECT *
FROM final
ORDER BY schema_and_object;
李白 2024-10-15 03:25:51

pg_constraint 包含数据库中的所有约束,您可以使用 confrelidconrelid 列出所有依赖表的 oid外键约束

查询如下所示

select confrelid,conrelid from pg_constraint where contype='f';

pg_constraint contains all constrains in the database you can list the oid of dependent tables using confrelid and conrelid from all all the foreign key constraints

query looks like this

select confrelid,conrelid from pg_constraint where contype='f';

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文