PostgreSQL
 sql >> Base de données >  >> RDS >> PostgreSQL

Comment trouver des tables héritées par programmation dans PostgreSQL ?

Puisque vous êtes sur une si ancienne version de PostgreSQL, vous devrez probablement utiliser une fonction PL/PgSQL pour gérer des profondeurs d'héritage> 1. Sur PostgreSQL moderne (ou même 8.4), vous utiliserez une expression de table commune récursive (WITH RECURSIVE ).

Le pg_catalog.pg_inherits le tableau est la clé. Donné :

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 résultat correct trouvera cc , dd , et ccdd , mais ne trouve pas notpp ou notshown .

Une requête à profondeur unique est :

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;

... mais cela ne trouvera que cc .

Pour l'héritage multi-profondeur (c'est-à-dire tableC hérite de tableB hérite de tableA ) vous devez étendre cela via un CTE récursif ou une boucle en PL/PgSQL, en utilisant les enfants de la dernière boucle comme parents dans la suivante.

Mettre à jour :Voici une version compatible 8.3 qui devrait trouver récursivement toutes les tables qui héritent directement ou indirectement d'un parent donné. Si l'héritage multiple est utilisé, il doit trouver toute table dont la table cible est l'un de ses parents à n'importe quel point de l'arborescence.

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;

Utilisation :

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

Voici la version CTE récursive, qui fonctionnera si vous mettez à jour Pg, mais ne fonctionnera pas sur votre version actuelle. C'est beaucoup plus propre 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);