2012-08-27 26 views

Respuesta

8

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

La tabla pg_catalog.pg_inherits es la clave. Teniendo en cuenta:

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 encontrar notpp o notshown.

Una consulta de simple fondo 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 sólo encontrará cc.

para la herencia multi-profundidad (es decir tableC hereda tableB hereda tableA) tiene que extender que a través de un CTE recursiva o un bucle en PL/PgSQL, utilizando los hijos del último bucle como progenitores en la siguiente.

Actualización: Aquí hay una versión compatible con 8.3 que debe encontrar recursivamente todas las tablas que heredan directa o indirectamente de un padre determinado. Si se usa herencia múltiple, debe 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 recursiva CTE, que funcionará si se actualiza Pg, pero no funcionará en su versión actual. Es mucho más limpio 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); 
+1

+1 por mencionar herencia múltiple. No pensé en eso. –

+0

Esta es una gran consulta. ¡Solo traté de ejecutarlo y funcionó perfecto! Modifiqué esto para acomodar nuestras convenciones de nombres. Muchas gracias por esto ... – Arun

+0

@Arun Me alegro de que haya ayudado. –

2

La siguiente instrucción recupera todas las tablas secundarias de la tabla public.base_table_name:

select bt.relname as table_name, bns.nspname as table_schema 
from pg_class ct 
    join pg_namespace cns on ct.relnamespace = cns.oid and cns.nspname = 'public' 
    join pg_inherits i on i.inhparent = ct.oid and ct.relname = 'base_table_name' 
    join pg_class bt on i.inhrelid = bt.oid 
    join pg_namespace bns on bt.relnamespace = bns.oid 

Se debe trabajar con un 8,3, aunque no estoy seguro al 100%.

+0

¡Funcionó como un encanto! Muchas gracias por esto – Arun

+0

@CraigRinger, gracias por su aporte, ¿podría decirme si es posible encontrar niños si hay herencia de varios niveles? – Arun

1

Para aquellos que están ejecutando una versión de PostgreSQL con el apoyo RECURSIVE aquí es una función que encuentra tablas para la tabla base especificada deriva.

CREATE OR REPLACE FUNCTION tables_derived_from(base_namespace name, base_table name) 
RETURNS TABLE (table_schema name, table_name name, oid oid) 
AS $BODY$ 
    WITH RECURSIVE inherited_id AS 
    (
     SELECT i.inhrelid AS oid 
     FROM pg_inherits i 
     JOIN pg_class base_t ON i.inhparent = base_t.oid 
     JOIN pg_namespace base_ns ON base_t.relnamespace = base_ns.oid 
     WHERE base_ns.nspname = base_namespace AND base_t.relname = base_table 

     UNION 

     SELECT i.inhrelid AS oid 
     FROM pg_inherits i 
     JOIN inherited_id b ON i.inhparent = b.oid 
    ) 
    SELECT child_ns.nspname as table_schema, child_t.relname as table_name, child_t.oid 
    FROM inherited_id i 
    JOIN pg_class child_t ON i.oid = child_t.oid 
    JOIN pg_namespace child_ns ON child_t.relnamespace = child_ns.oid 
    ORDER BY 1, 2, 3; 
$BODY$ LANGUAGE sql STABLE; 
1

Es importante señalar que una mesa puede heredar múltiples tablas, y ninguna de las soluciones que se indican realmente exponer a eso; simplemente caminan por el árbol de un padre soltero. Considere:

CREATE TABLE a(); 
CREATE TABLE b(); 
CREATE TABLE ab_() INHERITS (a,b); 
CREATE TABLE ba_() INHERITS (b,a); 
CREATE TABLE ab__() INHERITS (ab_); 
CREATE TABLE ba__() INHERITS (ba_); 
CREATE TABLE ab_ba_() INHERITS (ab_, ba_); 
CREATE TABLE ba_ab_() INHERITS (ba_, ab_); 

WITH RECURSIVE inh AS (
     SELECT i.inhparent::regclass, i.inhrelid::regclass, i.inhseqno FROM pg_catalog.pg_inherits i WHERE inhparent = 'a'::regclass 
     UNION 
     SELECT i.inhparent::regclass, i.inhrelid::regclass, i.inhseqno FROM inh INNER JOIN pg_catalog.pg_inherits i ON (inh.inhrelid = i.inhparent) 
) SELECT * FROM inh; 
inhparent | inhrelid | inhseqno 
-----------+----------+---------- 
a   | ab_  |  1 
a   | ba_  |  2 
ab_  | ab__  |  1 
ba_  | ba__  |  1 
ab_  | ab_ba_ |  1 
ba_  | ab_ba_ |  2 
ba_  | ba_ab_ |  1 
ab_  | ba_ab_ |  2 
(8 rows) 

en cuenta que b no aparece en absoluto lo cual es incorrecto, ya que ambos ab_ y BA_ heredan b.

Sospecho que la "mejor" forma de manejar esto sería una columna que es texto [] y contiene (matriz [inhparent :: regclass]) :: texto para cada tabla. Eso le daría algo así como

inhrelid path 
ab_  {"{a,b}"} 
ba_  {"{b,a}"} 
ab_ba_  {"{a,b}","{b,a}"} 

Aunque obviamente no es lo ideal, que por lo menos expondría a la ruta de herencia completa y le permitirá acceder a él con suficientes gimnasia. Desafortunadamente, construir eso no es para nada fácil.

Una alternativa algo más simple es no incluir la ruta de herencia completa en cada nivel, solo cada tabla dirige a los padres. Eso le daría esto:

inhrelid parents 
ab_   {a,b} 
ba_   {b,a} 
ab_ba_  {ab_,ba_} 
Cuestiones relacionadas