sql >> Databáze >  >> RDS >> PostgreSQL

Jak najít zděděné tabulky programově v PostgreSQL?

Vzhledem k tomu, že používáte tak starou verzi PostgreSQL, budete pravděpodobně muset použít funkci PL/PgSQL ke zpracování hloubky dědičnosti> 1. Na moderním PostgreSQL (nebo dokonce 8.4) byste použili rekurzivní společný tabulkový výraz (WITH RECURSIVE ).

pg_catalog.pg_inherits stůl je klíč. Vzhledem k:

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

Správný výsledek najde cc , dd a ccdd , ale nenajdete notpp nebo notshown .

Dotaz s jednou hloubkou je:

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;

... ale tím se najde pouze cc .

Pro vícehloubkovou dědičnost (tj. tableC zdědí tableB zdědí tableA ) to musíte rozšířit pomocí rekurzivního CTE nebo smyčky v PL/PgSQL s použitím potomků poslední smyčky jako rodičů v další.

Aktualizovat :Zde je verze kompatibilní s 8.3, která by měla rekurzivně najít všechny tabulky, které dědí přímo nebo nepřímo od daného rodiče. Pokud se použije vícenásobná dědičnost, měla by najít jakoukoli tabulku, která má cílovou tabulku jako jednoho ze svých rodičů v libovolném bodě stromu.

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;

Použití:

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

Zde je rekurzivní verze CTE, která bude fungovat, pokud aktualizujete Pg, ale nebude fungovat na vaší aktuální verzi. IMO je mnohem čistší.

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. Použití poddotazu v příkazu Check v Oracle

  2. CHYBA:další data za posledním očekávaným sloupcem při použití PostgreSQL COPY

  3. Levé spojení ON podmínka A další syntaxe podmínky v Doctrine

  4. Oprava chyby 1064 (42000) při použití operátora MINUS v MariaDB