6

テーブル継承が使用されているPostgreSQL8.3データベースがあります。クエリを使用してベーステーブルから継承されたスキーマ名とともに、すべてのテーブルのリストを取得したいと思います。PGSQLを使用してこれを取得する方法はありますか?

4

4 に答える 4

10

このような古いバージョンのPostgreSQLを使用しているため、おそらくPL / PgSQL関数を使用して1を超える継承深度を処理する必要があります。最新のPostgreSQL(または8.4)では、再帰共通テーブル式(WITH RECURSIVE)を使用します。 。

pg_catalog.pg_inheritsテーブルが鍵です。与えられた:

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

正しい結果では、、、およびが検出されますがcc、またはは検出されません。ddccddnotppnotshown

単一の深さのクエリは次のとおりです。

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;

...しかし、これは。のみを検索しますcc

マルチデプス継承(つまり、tableC継承tableB継承tableA)の場合、再帰CTEまたはPL / PgSQLのループを介して、最後のループの子を次のループの親として使用して、それを拡張する必要があります。

更新:これは、特定の親から直接または間接的に継承するすべてのテーブルを再帰的に検索する必要がある8.3互換バージョンです。多重継承が使用されている場合、ツリーの任意の時点で、ターゲットテーブルを親の1つとして持つテーブルを見つける必要があります。

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;

使用法:

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

これが再帰CTEバージョンです。これは、Pgを更新すると機能しますが、現在のバージョンでは機能しません。それははるかにクリーンな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);
于 2012-08-27T09:37:26.003 に答える
2

次のステートメントは、テーブルのすべての子テーブルを取得しますpublic.base_table_name

select bt.relname as table_name, bns.nspname as table_schema 
from pg_class ct 
    join pg_namespace cns on ct.relnamespace = cns.oid and cns.nspname = 'public' 
    join pg_inherits i on i.inhparent = ct.oid and ct.relname = 'base_table_name' 
    join pg_class bt on i.inhrelid = bt.oid 
    join pg_namespace bns on bt.relnamespace = bns.oid

100%確実ではありませんが、8.3で動作するはずです。

于 2012-08-27T09:34:42.317 に答える
1

サポートされているバージョンのPostgreSQLを実行している人RECURSIVEのために、指定されたベーステーブルの派生テーブルを検索する関数があります。

CREATE OR REPLACE FUNCTION tables_derived_from(base_namespace name, base_table name)
RETURNS TABLE (table_schema name, table_name name, oid oid)
AS $BODY$
    WITH RECURSIVE inherited_id AS
    (
        SELECT i.inhrelid AS oid
        FROM pg_inherits i
        JOIN pg_class base_t ON i.inhparent = base_t.oid
        JOIN pg_namespace base_ns ON base_t.relnamespace = base_ns.oid
        WHERE base_ns.nspname = base_namespace AND base_t.relname = base_table

        UNION

        SELECT i.inhrelid AS oid
        FROM pg_inherits i
        JOIN inherited_id b ON i.inhparent = b.oid
    )
    SELECT child_ns.nspname as table_schema, child_t.relname as table_name, child_t.oid
    FROM inherited_id i
    JOIN pg_class child_t ON i.oid = child_t.oid 
    JOIN pg_namespace child_ns ON child_t.relnamespace = child_ns.oid
    ORDER BY 1, 2, 3;
$BODY$ LANGUAGE sql STABLE;
于 2013-08-12T17:36:45.580 に答える
1

1つのテーブルが複数のテーブルを継承できることに注意することが重要です。リストされているソリューションのいずれも実際にはそれを公開していません。彼らはひとり親の木を歩いているだけです。検討:

CREATE TABLE a();
CREATE TABLE b();
CREATE TABLE ab_() INHERITS (a,b);
CREATE TABLE ba_() INHERITS (b,a);
CREATE TABLE ab__() INHERITS (ab_);
CREATE TABLE ba__() INHERITS (ba_);
CREATE TABLE ab_ba_() INHERITS (ab_, ba_);
CREATE TABLE ba_ab_() INHERITS (ba_, ab_);

WITH RECURSIVE inh AS (
        SELECT i.inhparent::regclass, i.inhrelid::regclass, i.inhseqno FROM pg_catalog.pg_inherits i WHERE inhparent = 'a'::regclass
        UNION
        SELECT i.inhparent::regclass, i.inhrelid::regclass, i.inhseqno FROM inh INNER JOIN pg_catalog.pg_inherits i ON (inh.inhrelid = i.inhparent)
) SELECT * FROM inh;
 inhparent | inhrelid | inhseqno 
-----------+----------+----------
 a         | ab_      |        1
 a         | ba_      |        2
 ab_       | ab__     |        1
 ba_       | ba__     |        1
 ab_       | ab_ba_   |        1
 ba_       | ab_ba_   |        2
 ba_       | ba_ab_   |        1
 ab_       | ba_ab_   |        2
(8 rows)

ab_とba_の両方がbを継承するため、bがまったく表示されないことに注意してください。これは正しくありません。

これを処理する「最良の」方法は、text []であり、各テーブルの(array [inhparent :: regclass])::textを含む列であると思われます。それはあなたに次のようなものを与えるでしょう

inhrelid   path
ab_        {"{a,b}"}
ba_        {"{b,a}"}
ab_ba_     {"{a,b}","{b,a}"}

明らかに理想的ではありませんが、それは少なくとも完全な継承パスを公開し、十分な体操でそれにアクセスできるようにします。残念ながら、それを構築することはまったく簡単ではありません。

もう少し簡単な方法は、各レベルに完全な継承パスを含めず、各テーブルのみが親を指示することです。それはあなたにこれを与えるでしょう:

inhrelid    parents
ab_         {a,b}
ba_         {b,a}
ab_ba_      {ab_,ba_}
于 2015-08-31T20:31:41.767 に答える