PostgreSQL
 sql >> Database >  >> RDS >> PostgreSQL

Come trovare le tabelle ereditate in modo programmatico in PostgreSQL?

Dato che sei su una versione così vecchia di PostgreSQL, probabilmente dovrai usare una funzione PL/PgSQL per gestire profondità di ereditarietà> 1. Su PostgreSQL moderno (o anche 8.4) useresti un'espressione di tabella comune ricorsiva (WITH RECURSIVE ).

Il pg_catalog.pg_inherits la tabella è la chiave. Dato:

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 risultato corretto troverà cc , dd e ccdd , ma non trovare notpp o notshown .

Una query a profondità singola è:

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;

... ma questo troverà solo cc .

Per l'ereditarietà multi-profondità (ad esempio tableC eredita tableB eredita tableA ) devi estenderlo tramite un CTE ricorsivo o un ciclo in PL/PgSQL, usando i figli dell'ultimo ciclo come genitori nel successivo.

Aggiorna :ecco una versione compatibile 8.3 che dovrebbe trovare ricorsivamente tutte le tabelle che ereditano direttamente o indirettamente da un determinato genitore. Se viene utilizzata l'ereditarietà multipla, dovrebbe trovare qualsiasi tabella che abbia la tabella di destinazione come uno dei suoi genitori in qualsiasi punto lungo l'albero.

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;

Utilizzo:

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

Ecco la versione ricorsiva CTE, che funzionerà se aggiorni Pg, ma non funzionerà con la tua versione corrente. È molto più pulito 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);