PostgreSQL
 sql >> Datenbank >  >> RDS >> PostgreSQL

Wie findet man geerbte Tabellen programmgesteuert in PostgreSQL?

Da Sie auf einer so alten Version von PostgreSQL arbeiten, müssen Sie wahrscheinlich eine PL/PgSQL-Funktion verwenden, um Vererbungstiefen von> 1 zu handhaben. Auf modernem PostgreSQL (oder sogar 8.4) würden Sie einen rekursiven allgemeinen Tabellenausdruck (WITH RECURSIVE ).

Die pg_catalog.pg_inherits Tisch ist der Schlüssel. Gegeben:

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

Ein korrektes Ergebnis findet cc , dd , und ccdd , aber notpp nicht finden oder notshown .

Eine Abfrage mit einfacher Tiefe ist:

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;

... aber das findet nur cc .

Für Multi-Depth-Vererbung (d. h. tableC erbt tableB erbt tableA ) müssen Sie das über einen rekursiven CTE oder eine Schleife in PL/PgSQL erweitern, indem Sie die Kinder der letzten Schleife als Eltern in der nächsten verwenden.

Aktualisieren :Hier ist eine 8.3-kompatible Version, die rekursiv alle Tabellen finden sollte, die direkt oder indirekt von einem bestimmten Elternteil erben. Wenn Mehrfachvererbung verwendet wird, sollte es an jedem Punkt entlang des Baums jede Tabelle finden, die die Zieltabelle als eine ihrer Eltern hat.

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;

Verwendung:

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

Hier ist die rekursive CTE-Version, die funktioniert, wenn Sie Pg aktualisieren, aber nicht auf Ihrer aktuellen Version. Es ist meiner Meinung nach viel sauberer.

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