sql >> Database >  >> RDS >> PostgreSQL

Hoe geërfde tabellen programmatisch te vinden in PostgreSQL?

Aangezien je zo'n oude versie van PostgreSQL hebt, zul je waarschijnlijk een PL/PgSQL-functie moeten gebruiken om overervingsdiepten van> 1 te verwerken. Op moderne PostgreSQL (of zelfs 8.4) zou je een recursieve algemene tabeluitdrukking (WITH RECURSIVE ).

De pg_catalog.pg_inherits tafel is de sleutel. Gegeven:

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

Een correct resultaat vindt u cc , dd , en ccdd , maar niet vinden notpp of notshown .

Een zoekopdracht met een enkele diepte is:

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;

... maar dit vindt alleen cc .

Voor overerving met meerdere diepten (bijv. tableC erft tableB erft tableA ) moet je dat uitbreiden via een recursieve CTE of een lus in PL/PgSQL, waarbij je de kinderen van de laatste lus als ouders gebruikt in de volgende.

Bijwerken :Hier is een 8.3-compatibele versie die recursief alle tabellen zou moeten vinden die direct of indirect van een bepaalde ouder erven. Als meervoudige overerving wordt gebruikt, zou het elke tabel moeten vinden die de doeltabel als een van de ouders heeft op elk punt in de boom.

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;

Gebruik:

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

Hier is de recursieve CTE-versie, die werkt als u Pg bijwerkt, maar niet voor uw huidige versie. Het is veel schoner 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. Bestanden uploaden van IPhone/IPad naar mysql DB?

  2. Webinar:nieuwe functies in Postgres 12 [vervolg]

  3. Hoe GREATEST() werkt in MariaDB

  4. Mysql:hoe krijg je alle rijen met meer dan een bepaald aantal decimalen na de punt?