sql >> Base de Datos >  >> RDS >> PostgreSQL

¿Cómo encontrar tablas heredadas programáticamente en PostgreSQL?

Dado que tiene una versión tan antigua de PostgreSQL, probablemente tendrá que usar una función PL/PgSQL para manejar profundidades de herencia de> 1. En PostgreSQL moderno (o incluso 8.4), usaría una expresión de tabla común recursiva (WITH RECURSIVE ).

El pg_catalog.pg_inherits La mesa es la clave. 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

Un resultado correcto encontrará cc , dd y ccdd , pero no encuentra notpp o notshown .

Una consulta de profundidad única es:

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;

... pero esto solo encontrará cc .

Para herencia de múltiples profundidades (es decir, tableC hereda tableB hereda tableA ) tienes que extender eso a través de un CTE recursivo o un bucle en PL/PgSQL, usando los hijos del último bucle como padres en el siguiente.

Actualizar :Aquí hay una versión compatible con 8.3 que debería encontrar recursivamente todas las tablas que heredan directa o indirectamente de un padre dado. Si se usa herencia múltiple, debería encontrar cualquier tabla que tenga la tabla de destino como uno de sus padres en cualquier punto del árbol.

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)

Aquí está la versión CTE recursiva, que funcionará si actualiza Pg, pero no funcionará en su versión actual. En mi opinión, es mucho más limpio.

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);