PostgreSQL
 sql >> Base de Dados >  >> RDS >> PostgreSQL

Como encontrar tabelas herdadas programaticamente no PostgreSQL?


Como você está em uma versão tão antiga do PostgreSQL, você provavelmente terá que usar uma função PL/PgSQL para lidar com profundidades de herança de> 1. No PostgreSQL moderno (ou mesmo 8.4) você usaria uma expressão de tabela comum recursiva (WITH RECURSIVE ).

O pg_catalog.pg_inherits mesa é a chave. Dado:
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

Um resultado correto encontrará cc , dd e ccdd , mas não encontra notpp ou notshown .

Uma consulta de profundidade única é:
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;

... mas isso só encontrará cc .

Para herança multi-profundidade (ou seja, tableC herda tableB herda tableA ) você precisa estender isso por meio de um CTE recursivo ou um loop em PL/PgSQL, usando os filhos do último loop como pais no próximo.

Atualizar :Aqui está uma versão compatível com 8.3 que deve encontrar recursivamente todas as tabelas que herdam direta ou indiretamente de um determinado pai. Se herança múltipla for usada, ela deverá localizar qualquer tabela que tenha a tabela de destino como um de seus pais em qualquer ponto da árvore.
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;

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

Aqui está a versão recursiva do CTE, que funcionará se você atualizar o Pg, mas não funcionará na sua versão atual. É muito mais limpo 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);