0

データベースに他のテーブルのインデックスを持つテーブルがあります。

以前、このインデックスを繰り返し実行しqueries on the tables indexed,ましたが、ご想像のとおり、これは多数のテーブルでは非常に低速です。

インデックステーブルのクエリの結果からテーブル式を作成して、インデックステーブルのクエリのを使用してFROMを使用してクエリを1つのステートメントとして記述できるかどうか疑問に思いlist of tables resultます。

ETA:PostgreSQLv9.0を使用しています。同じクエリで複数のテーブルを一度に1つずつ繰り返すことでクエリを実行しています(これは遅いです)。インデックステーブルから選択されたすべてのテーブルのリストである1つのテーブル式を使用してすべてのテーブルをクエリする方法がある場合は、これを高速化したいと思います。

私の(簡略化された)テーブルは「tabledata」であり、同一のスキーマテーブルA、B、C、D、E、F、Gのリストと、それぞれに対してブール値の「有効」が含まれています。'enabled'がtrueであるすべての文字付きテーブルをクエリしたいと思います。一度に1つずつクエリを繰り返すのではなく、1つのクエリを使用することをお勧めします。基本的に、以下によって返されるテーブルを照会します。

SELECT tablename FROM tabledata WHERE enabled = TRUE`

ETA2:クエリツールに以下を入力しました:

CREATE FUNCTION f_all_tables()
  RETURNS SETOF A AS 
$body$
DECLARE 
    _tbl oid;
BEGIN 
FOR _tbl IN 
    SELECT tablename::regclass
    FROM   tabledata 
    WHERE  enabled 
LOOP 
    RETURN QUERY EXECUTE  '
    SELECT * FROM ' || _tbl; 
END LOOP; 
END;

$body$ language plpgsql; 

SELECT * FROM f_all_tables();

そしてエラーが発生します:

ERROR:  invalid input syntax for type oid: "A"
CONTEXT:  PL/pgSQL function "f_all_tables" line 6 at FOR over SELECT rows

ここAで、はの最初のテーブル名ですtabledata

ETA3:

以下の2番目のソリューションを実装しましたが、機能します。おかげでサンプルコード:

CREATE TABLE tabledata2 
(
  tablename character(64) NOT NULL,
  enabled boolean
)
WITH (
  OIDS=FALSE
);
ALTER TABLE tabledata2
  OWNER TO postgres;

CREATE TABLE AAAAAA
(
  enabled boolean
)
WITH (
  OIDS=FALSE
);
ALTER TABLE AAAAAA
  OWNER TO postgres;
CREATE TABLE AAAAAB
(
  enabled boolean
)
WITH (
  OIDS=FALSE
);
ALTER TABLE AAAAAB
  OWNER TO postgres;

INSERT INTO tabledata2 VALUES ('AAAAAA', 'true');
INSERT INTO tabledata2 VALUES ('AAAAAB', 'true');
INSERT INTO AAAAAA VALUES ('true');
INSERT INTO AAAAAB VALUES ('false');

CREATE FUNCTION f_all_tables() 
  RETURNS SETOF AAAAAA AS  
$body$ 
DECLARE  
    _tbl regclass; 
BEGIN  
FOR _tbl IN  
    SELECT tablename::regclass 
    FROM   tabledata2  
    WHERE  enabled
LOOP  
    RETURN QUERY EXECUTE  ' 
    SELECT * FROM ' || _tbl;  
END LOOP;  
END; 

$body$ language plpgsql;  

SELECT * FROM f_all_tables(); 
4

2 に答える 2

3

あなたのコメントから、すべての候補テーブルが同じレイアウトを共有していることがわかりました。

あなたはすでにあなた自身を知っています、適切な方法はすべての行を保持する1つのテーブルを持ち、おそらくそれらのタイプをマークするための追加の列を持つことです。

1つのテーブルから行を取得する

CREATE FUNCTION f_table(int)
  RETURNS SETOF A AS
$body$
BEGIN

    RETURN QUERY EXECUTE '
    SELECT * FROM ' || tablename::regclass FROM mytables WHERE id = $1;

END;
$body$ language plpgsql;

電話:

SELECT * FROM f_table(42);

主なポイント:

  • テーブルと同じように「table-function」(関数の戻りSETOF値)をクエリできます。

  • テーブルは同じレイアウトを共有します。したがって、戻りタイプを定義でき、呼び出しごとに列定義リストを入力する必要はありません。

  • PostgreSQLのすべてのテーブルに同じ名前の複合タイプがあることを知っておく必要があります。そのため、テーブルの1つの名前(A私の例では)を戻り型として使用でき、それが機能します。

  • テーブル名には、の代わりにキャストをregclass使用しますquote_ident(tablename)。SQLインジェクションからも保護し、のようなスキーマ修飾テーブル名に対しても機能しますmyschma.mytablequote_ident()良い考えですが、そのような場合は失敗します。

  • 動的SQLを使用する関数を定義することはできませんSTABLEマニュアルで関数を作成する方法の詳細。


すべてのテーブルから行を取得する

(すべて同じ基本タイプです。)
まず、純粋なSQLでは、テーブルの動的リストを使用してこれを行う方法はありません。

CREATE FUNCTION f_all_tables()
  RETURNS SETOF A AS
$body$
DECLARE
    _tbl regclass;
BEGIN

FOR _tbl IN
    SELECT tablename::regclass
    FROM   tabledata
    WHERE  enabled
LOOP
    RETURN QUERY EXECUTE '
    SELECT * FROM ' || _tbl;
END LOOP;

END;
$body$ language plpgsql;

電話:

SELECT * FROM f_all_tables();

この一連のテーブルのメンバーが変更されない場合は、1つの大きな醜いUNIONSELECTを記述できます。

SELECT * FROM A
UNION ALL
SELECT * FROM B
...

UNION ALL結果にすべての重複を保持します。

于 2012-04-13T13:03:27.907 に答える
1

何かのようなもの:

SELECT * FROM (SELECT tablename FROM mytables WHERE id = 42);

?それは実際には不可能です。

最も明白な方法は、EXECUTEを使用して動的ステートメントを使用することです。テーブルの名前を取り、すべての行のすべての列を返す関数を作成できます。次に、次の列定義リストを指定する必要があります。

CREATE FUNCTION select_from_table(TEXT) RETURNS SETOF RECORD
STABLE LANGUAGE 'plpgsql' AS
$$
BEGIN
    RETURN QUERY EXECUTE 'SELECT * FROM ' || quote_ident($1);
END;
$$;

SELECT * FROM select_from_table('pg_namespace') AS s(nspname name, nspowner oid, nspacl aclitem[]);

あなたはこれがどれほど醜いかについて考えなければなりません。すべてのテーブルが同じスキーマを持つ場合は、適切な型を返すことで少しクリーンアップできます(呼び出し元に毎回大きな醜い列定義リストを指定させる代わりに)。

さらに、常に特定の方法でフィルタリングしたい場合は、それを実行させることができます。

ただし、一般的には、達成しようとしていることと、よりSQLの方法でそれを実行できるかどうかについても考慮する必要があります。

于 2012-04-12T22:29:49.650 に答える