如何列出受级联删除影响的表

Pet*_*man 14 postgresql

我正在尝试在15+表上执行级联删除,但我不确定所有必需的外键是否已正确配置.我想检查缺少的约束,而无需手动查看每个约束.

有没有办法获得一个受级联删除查询影响的表列表?

kli*_*lin 17

使用pg_depend.例:

create table master (id int primary key);
create table detail_1 (id int, master_id int references master(id) on delete restrict);
create table detail_2 (id int, master_id int references master(id) on delete cascade);

select pg_describe_object(classid, objid, objsubid)
from pg_depend 
where refobjid = 'master'::regclass and deptype = 'n';

                  pg_describe_object
------------------------------------------------------
 constraint detail_1_master_id_fkey on table detail_1
 constraint detail_2_master_id_fkey on table detail_2
(2 rows)
Run Code Online (Sandbox Code Playgroud)

deptype = 'n' 手段:

DEPENDENCY NORMAL - 单独创建的对象之间的正常关系.可以删除依赖对象而不影响引用的对象.只能通过指定CASCADE来删除引用的对象,在这种情况下也会删除依赖对象.

使用pg_get_constraintdef()得到约束定义:

select 
    pg_describe_object(classid, objid, objsubid), 
    pg_get_constraintdef(objid)
from pg_depend 
where refobjid = 'master'::regclass and deptype = 'n';


                  pg_describe_object                  |                       pg_get_constraintdef
------------------------------------------------------+------------------------------------------------------------------
 constraint detail_1_master_id_fkey on table detail_1 | FOREIGN KEY (master_id) REFERENCES master(id) ON DELETE RESTRICT
 constraint detail_2_master_id_fkey on table detail_2 | FOREIGN KEY (master_id) REFERENCES master(id) ON DELETE CASCADE
(2 rows)
Run Code Online (Sandbox Code Playgroud)

要找到级联依赖的完整链,我们应该使用递归并查看目录pg_constraint以获取id依赖表.

with recursive chain as (
    select classid, objid, objsubid, conrelid
    from pg_depend d
    join pg_constraint c on c.oid = objid
    where refobjid = 'the_table'::regclass and deptype = 'n'
union all
    select d.classid, d.objid, d.objsubid, c.conrelid
    from pg_depend d
    join pg_constraint c on c.oid = objid
    join chain on d.refobjid = chain.conrelid and d.deptype = 'n'
    )
select pg_describe_object(classid, objid, objsubid), pg_get_constraintdef(objid)
from chain;
Run Code Online (Sandbox Code Playgroud)

  • 尝试查询的递归版本。 (2认同)

Vao*_*sun 8

是的。您可以在事务和回滚中截断级联。注意ROLLBACK是保存数据的按键。postgres 将告诉NOTICE您哪些其他引用表将受到影响。

postgres=# begin;
BEGIN
postgres=# truncate table a cascade;
NOTICE:  truncate cascades to table "b"
TRUNCATE TABLE
postgres=# rollback;
ROLLBACK
Run Code Online (Sandbox Code Playgroud)


bma*_*bma 7

使用传递闭包,可以确定引用表和被引用表。需要注意的是,此查询/视图依赖于外键的存在来确定依赖关系,并且如果缺少 FK ,则不会找到表(后者似乎是 OP 所要求的)。

通过外键的表依赖

CREATE OR REPLACE VIEW table_dependencies AS (
WITH RECURSIVE t AS (
    SELECT
        c.oid AS origin_id,
        c.oid::regclass::text AS origin_table,
        c.oid AS referencing_id,
        c.oid::regclass::text AS referencing_table,
        c2.oid AS referenced_id,
        c2.oid::regclass::text AS referenced_table,
        ARRAY[c.oid::regclass,c2.oid::regclass] AS chain
    FROM pg_catalog.pg_constraint AS co
    INNER JOIN pg_catalog.pg_class AS c ON c.oid = co.conrelid
    INNER JOIN pg_catalog.pg_class AS c2 ON c2.oid = co.confrelid
--     Add this line as an input parameter if you want to make a one-off query
--     WHERE c.oid::regclass::text = 'YOUR TABLE'
    UNION ALL
    SELECT
        t.origin_id,
        t.origin_table,
        t.referenced_id AS referencing_id,
        t.referenced_table AS referencing_table,
        c3.oid AS referenced_id,
        c3.oid::regclass::text AS referenced_table,
        t.chain || c3.oid::regclass AS chain
    FROM pg_catalog.pg_constraint AS co
    INNER JOIN pg_catalog.pg_class AS c3 ON c3.oid = co.confrelid
    INNER JOIN t ON t.referenced_id = co.conrelid
    WHERE
        -- prevent infinite recursion by pruning paths where the last entry in
        -- the path already appears somewhere else in the path
        NOT (
            ARRAY[ t.chain[array_upper(t.chain, 1)] ] -- an array containing the last element
            <@                                        -- "is contained by"
            t.chain[1:array_upper(t.chain, 1) - 1]    -- a slice of the chain,
                                                      -- from element 1 to n-1
        )
)
SELECT  origin_table,
        referenced_table,
        array_upper(chain,1) AS "depth",
        array_to_string(chain,',') as chain
FROM t
);
Run Code Online (Sandbox Code Playgroud)

引用特定表的表

SELECT * FROM table_dependencies WHERE origin_table = 'clients';
Run Code Online (Sandbox Code Playgroud)

与“clients”表直接相关的表

SELECT *
FROM table_dependencies
WHERE referenced_table = 'clients'
AND depth = 2
ORDER BY origin_table;
Run Code Online (Sandbox Code Playgroud)