2012-08-27 4 views

答えて

8

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 

正しい結果がccdd、およびccddを見つけるが、notppまたはnotshownを見つけることができません。

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を見つける:

単一の深さのクエリがあります。マルチ深さの継承のために

(すなわちtableCtableBtableAを継承継承)あなたは次の中の親としての最後のループの子供を使用して、再帰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) 

ここでは、Pgのを更新した場合に動作します再帰CTEのバージョンは、ですが、あなたの現在のバージョンでは動作しません。はるかにクリーンなIMOです。 RECURSIVEサポート付きのPostgreSQLのバージョンを実行している人のために

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

複数の継承を示す+1。私はそれを考えなかった。 –

+0

これは素晴らしい質問です。私はそれを実行しようとしたが、それは完璧に働いた!これを私たちの命名規則に合わせて修正しました。こんにちは、ありがとうございました。 – Arun

+0

@Arun Glad it helped。 –

2

次の文は、表public.base_table_nameのすべての子テーブルを取得します。私は100%確実ではないですが、それは8.3で動作するはず

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 

+0

チャームのように働いた!これに感謝します。 – Arun

+0

@CraigRinger、その入力をありがとう、マルチレベル継承がある場合、子供を見つけることが可能かどうか教えてください。 – Arun

1

ここで指定したベーステーブルの派生テーブルを検出機能があります。

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

これは、1つのテーブルが複数テーブルを継承していない、と本当にそれを公開記載されているソリューションのどれもできることに注意することが重要です。彼らは片親の木を歩いているだけです。考えてみましょう:bはab_とba_継承bの両方として、間違っていたすべてので表示されないことを

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) 

お知らせ。

これを処理する "最良の"方法は、text []で、各テーブルの(配列[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_} 
関連する問題