如何在PostgreSQL中以编程方式查找继承的表?

Aru*_*run 5 postgresql inheritance

我有一个PostgreSQL 8.3数据库,其中正在使用表继承.我想获得所有表的列表及其模式名称,该名称是使用查询从基表继承的.我们有什么方法可以使用PGSQL获得这个吗?

Cra*_*ger 9

由于您使用的是旧版本的PostgreSQL,您可能必须使用PL/PgSQL函数来处理> 1的继承深度.在现代PostgreSQL(甚至8.4)上,您将使用递归公用表表达式(WITH RECURSIVE) .

pg_catalog.pg_inherits表是关键.鉴于:

create table pp( );     -- The parent we'll search for
CREATE TABLE notpp(); -- Another root for multiple inheritance
create table cc( ) inherits (pp); -- a 1st level child of pp
create table dd( ) inherits (cc,notpp); -- a 2nd level child of pp that also inherits aa
create table notshown( ) inherits (notpp); -- Table that inherits only notpp
create table ccdd () inherits (cc,dd) -- Inheritance is a graph not a tree; join node
Run Code Online (Sandbox Code Playgroud)

正确的结果将找到cc,ddccdd,但找不到notppnotshown.

单深度查询是:

SELECT pg_namespace.nspname, pg_class.relname 
FROM pg_catalog.pg_inherits 
  INNER JOIN pg_catalog.pg_class ON (pg_inherits.inhrelid = pg_class.oid) 
  INNER JOIN pg_catalog.pg_namespace ON (pg_class.relnamespace = pg_namespace.oid) 
WHERE inhparent = 'pp'::regclass;
Run Code Online (Sandbox Code Playgroud)

......但这只能找到cc.

对于多深度继承(即tableC继承tableB继承tableA),你必须通过递归CTE或PL/PgSQL中的循环来扩展它,使用最后一个循环的子节点作为下一个循环的父节点.

更新:这是一个8.3兼容版本,应该递归地查找直接或间接从给定父级继承的所有表.如果使用多重继承,它应该在树的任何位置找到任何具有目标表作为其父节点之一的表.

CREATE OR REPLACE FUNCTION find_children(oid) RETURNS SETOF oid as $$
SELECT i.inhrelid FROM pg_catalog.pg_inherits i WHERE i.inhparent = $1
UNION
SELECT find_children(i.inhrelid) FROM pg_catalog.pg_inherits i WHERE i.inhparent = $1;
$$ LANGUAGE 'sql' STABLE;

CREATE OR REPLACE FUNCTION find_children_of(parentoid IN regclass, schemaname OUT name, tablename OUT name) RETURNS SETOF record AS $$
SELECT pg_namespace.nspname, pg_class.relname 
        FROM find_children($1) inh(inhrelid) 
          INNER JOIN pg_catalog.pg_class ON (inh.inhrelid = pg_class.oid) 
          INNER JOIN pg_catalog.pg_namespace ON (pg_class.relnamespace = pg_namespace.oid);
$$ LANGUAGE 'sql' STABLE;
Run Code Online (Sandbox Code Playgroud)

用法:

regress=# SELECT * FROM find_children_of('pp'::regclass);
 schemaname | tablename 
------------+-----------
 public     | cc
 public     | dd
 public     | ccdd
(3 rows)
Run Code Online (Sandbox Code Playgroud)

这是递归CTE版本,如果您更新Pg将会起作用,但不适用于您当前的版本.这是更清洁的IMO.

WITH RECURSIVE inh AS (
        SELECT i.inhrelid FROM pg_catalog.pg_inherits i WHERE inhparent = 'pp'::regclass
        UNION
        SELECT i.inhrelid FROM inh INNER JOIN pg_catalog.pg_inherits i ON (inh.inhrelid = i.inhparent)
)
SELECT pg_namespace.nspname, pg_class.relname 
    FROM inh 
      INNER JOIN pg_catalog.pg_class ON (inh.inhrelid = pg_class.oid) 
      INNER JOIN pg_catalog.pg_namespace ON (pg_class.relnamespace = pg_namespace.oid);
Run Code Online (Sandbox Code Playgroud)