PostgreSQL
 sql >> Baza danych >  >> RDS >> PostgreSQL

Jak programowo znaleźć dziedziczone tabele w PostgreSQL?

Ponieważ jesteś na tak starej wersji PostgreSQL, prawdopodobnie będziesz musiał użyć funkcji PL/PgSQL do obsługi głębokości dziedziczenia> 1. We współczesnym PostgreSQL (lub nawet 8.4) użyjesz rekurencyjnego wyrażenia tabelowego (WITH RECURSIVE ).

pg_catalog.pg_inherits stół jest kluczem. Biorąc pod uwagę:

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

Prawidłowy wynik znajdzie cc , dd i ccdd , ale nie znajdź notpp lub notshown .

Zapytanie o pojedynczej głębokości to:

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 to znajdzie tylko cc .

Dla dziedziczenia wielogłębokiego (np. tableC dziedziczy tableB dziedziczy tableA ) musisz to rozszerzyć za pomocą rekurencyjnego CTE lub pętli w PL/PgSQL, używając dzieci ostatniej pętli jako rodziców w następnej.

Aktualizacja :Oto wersja kompatybilna z 8.3, która powinna rekurencyjnie znaleźć wszystkie tabele dziedziczące bezpośrednio lub pośrednio po danym rodzicu. Jeśli używane jest dziedziczenie wielokrotne, powinno znaleźć dowolną tabelę, której tabela docelowa jest jednym z jej rodziców w dowolnym punkcie drzewa.

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;

Użycie:

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

Oto rekurencyjna wersja CTE, która będzie działać, jeśli zaktualizujesz Pg, ale nie będzie działać w obecnej wersji. To znacznie czystsze 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. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Dlaczego w PostgreSQL typu enum array dozwolone są wartości null?

  2. Najlepsze praktyki w zakresie replikacji PostgreSQL — część 2

  3. Jak skonfigurować PostgreSQL dla Play 2.0?

  4. Słaba wydajność zapisu dataframe do Postgresql

  5. Konwertuj tablicę PostgreSQL na tablicę PHP