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

Hvordan finder man nedarvede tabeller programmatisk i PostgreSQL?

Da du er på en så gammel version af PostgreSQL, bliver du sandsynligvis nødt til at bruge en PL/PgSQL-funktion til at håndtere arvedybder på> 1. På moderne PostgreSQL (eller endda 8.4) ville du bruge et rekursivt almindeligt tabeludtryk (WITH RECURSIVE ).

pg_catalog.pg_inherits bord er nøglen. Givet:

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

Et korrekt resultat vil finde cc , dd og ccdd , men ikke finde notpp eller notshown .

En enkelt-dybde-forespørgsel er:

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;

... men dette vil kun finde cc .

Til multi-depth arv (dvs. tableC arver tableB arver tableA ) du skal udvide det via en rekursiv CTE eller en loop i PL/PgSQL, ved at bruge børnene i den sidste loop som forældre i den næste.

Opdater :Her er en 8.3-kompatibel version, der rekursivt skulle finde alle tabeller, der arver direkte eller indirekte fra en given forælder. Hvis multipel nedarvning bruges, bør den finde enhver tabel, der har måltabellen som en af ​​sine forældre på et hvilket som helst tidspunkt langs træet.

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;

Brug:

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

Her er den rekursive CTE-version, som vil fungere, hvis du opdaterer Pg, men som ikke fungerer på din nuværende version. Det er meget renere 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. Aggregeringsfunktion til at få forskellen eller forholdet mellem to rækker i rækkefølge

  2. Er der en ækvivalent til sp_getapplock, sp_releaseapplock i oracle

  3. Skift standard dato-tidsformat på en enkelt database i SQL Server

  4. Er der en måde med MySQL at flette flere forespørgsler til den samme tabel for at få de forskellige resultater i deres egne rækker?