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