sql >> Databasteknik >  >> RDS >> PostgreSQL

Hur hittar man ärvda tabeller programmässigt i PostgreSQL?

Eftersom du använder en så gammal version av PostgreSQL måste du förmodligen använda en PL/PgSQL-funktion för att hantera arvsdjup på> 1. På modern PostgreSQL (eller till och med 8.4) skulle du använda ett rekursivt vanligt tabelluttryck (WITH RECURSIVE ).

pg_catalog.pg_inherits bordet är nyckeln. 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

Ett korrekt resultat kommer att hitta cc , dd och ccdd , men inte hitta notpp eller notshown .

En enkel djup fråga är:

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 det här hittar bara cc .

För flerdjupsarv (dvs tableC ärver tableB ärver tableA ) du måste förlänga det via en rekursiv CTE eller en loop i PL/PgSQL, med barnen i den sista loopen som föräldrar i nästa.

Uppdatera :Här är en 8.3-kompatibel version som rekursivt bör hitta alla tabeller som ärver direkt eller indirekt från en given förälder. Om multipelarv används bör den hitta vilken tabell som helst som har måltabellen som en av sina föräldrar när som helst längs trädet.

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;

Användning:

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

Här är den rekursiva CTE-versionen, som fungerar om du uppdaterar Pg, men som inte fungerar på din nuvarande version. Det är mycket renare 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. Kan inte binda argument vid index 2 eftersom indexet ligger utanför intervallet

  2. Mysql - hitta konversation som endast hålls av två användare

  3. 7 bra tekniska vanor som alla arbetsgivare bör ta till sig

  4. Använder MySQLi från en annan klass i PHP