4

私のデータベースは、クライアントに基づいてスキーマに分割されています(つまり、各クライアントには、同じデータ構造を持つ独自のスキーマがあります)。

また、ターゲットにするスキーマがわからない外部アクションもあります。これは、クライアントの概念がなく、どのクライアントのセットで動作しているかがわからないシステムの別の部分に由来します。処理する前に、リクエストがターゲットにする必要のあるスキーマを見つける必要があります

適切なスキーマを見つけるにはR、特定の一意のID(文字列)を持つレコードを保持しているスキーマを見つける必要があります

私の理解から、次の

SET search_path TO schema1,schema2,schema3,...

schema1(またはテーブルに一致する最初のスキーマ)のテーブルのみを調べ、グローバル検索は行いません。

すべてのスキーマをグローバル検索する方法はありますか、それともforループを使用して、一度に1つずつすべてのスキーマを反復処理する必要がありますか?

4

3 に答える 3

5

これには継承を使用できます。(必ず制限事項を考慮してください。)

この小さなデモを考えてみましょう:

CREATE SCHEMA master;  -- no access of others ..

CREATE SEQUENCE master.myseq;  -- global sequence to have globally unique id
CREATE table master.tbl (
  id int primary key DEFAULT nextval('master.myseq')
, foo text);

CREATE SCHEMA x;
CREATE table x.tbl() INHERITS (master.tbl);
INSERT INTO  x.tbl(foo) VALUES ('x');

CREATE SCHEMA y;
CREATE table y.tbl() INHERITS (master.tbl);
INSERT INTO  y.tbl(foo) VALUES ('y');


SELECT * FROM x.tbl;  -- returns 'x'
SELECT * FROM y.tbl;  -- returns 'y'
SELECT * FROM master.tbl;  -- returns 'x' and 'y' <-- !!

-- clean it all up:
-- DROP SCHEMA x, y, master CASCADE;

ここで、特定の行が存在するテーブルを実際に識別するには、次を使用しますtableoid

SELECT *, tableoid::regclass AS table_name
FROM   master.tbl
WHERE  id = 2;

結果:

id | foo | table_name
---+-----+-----------
2  | y   | y.tbl

tableoidを使用してシステム カタログにクエリを実行することにより、からソース スキーマを取得できますtableoid。(表示名は の設定により異なりますsearch_path。)

SELECT n.nspname 
FROM   master.tbl   t
JOIN   pg_class     c ON c.oid = t.tableoid
JOIN   pg_namespace n ON c.relnamespace = n.oid
WHERE  t.id = 2;

これは、多くの個別のテーブルをループするよりもはるかに高速です。

于 2012-10-15T19:13:31.423 に答える
1

すべての名前空間を反復処理する必要があります。この情報の多くは、pg_*システム カタログから取得できます。理論的には、データベースと通信せずにリクエスト時にクライアント -> スキーマ マッピングを解決できるはずなので、最初の SQL 呼び出しは次のようになります。

SET search_path = client1,global_schema;
于 2012-10-15T19:04:39.723 に答える
1

テーブルを再構築できる場合、Erwin のソリューションがおそらく望ましいと思いますが、スキーマの変更を必要としない代替手段は、システム カタログ情報に基づいて動的 SQL を使用してテーブルをスキャンする PL/PgSQL 関数を作成することです。

与えられた:

CREATE SCHEMA a;
CREATE SCHEMA b;

CREATE TABLE a.testtab ( searchval text );
CREATE TABLE b.testtab (LIKE a.testtab);

INSERT INTO a.testtab(searchval) VALUES ('ham');
INSERT INTO b.testtab(searchval) VALUES ('eggs');

次の PL/PgSQL 関数は_tabname、値が_colname等しいという名前のテーブルを含むすべてのスキーマを検索し_value、最初に一致したスキーマを返します。

CREATE OR REPLACE FUNCTION find_schema_for_value(_tabname text, _colname text, _value text) RETURNS text AS $$
DECLARE
    cur_schema text;
    foundval integer;
BEGIN
    FOR cur_schema IN 
      SELECT nspname 
      FROM pg_class c 
      INNER JOIN pg_namespace n ON (c.relnamespace = n.oid) 
      WHERE c.relname = _tabname AND c.relkind = 'r'
    LOOP
      EXECUTE 
        format('SELECT 1 FROM %I.%I WHERE %I = $1', 
            cur_schema, _tabname, _colname
        ) INTO foundval USING _value;
      IF foundval = 1 THEN
        RETURN cur_schema;
      END IF;
    END LOOP;
    RETURN NULL;
END;
$$ LANGUAGE 'plpgsql';

一致するものがない場合は、null が返されます。複数の一致がある場合、結果はそれらの 1 つになりますが、どれが一致するかは保証されません。ORDER BYアルファベット順などで最初のものを返す (たとえば) 場合は、スキーマ クエリに句を追加します。関数は、すべての一致を返したい場合に返すようsetof textに簡単に変更されます。RETURN NEXT cur_schema

regress=# SELECT find_schema_for_value('testtab','searchval','ham');
 find_schema_for_value 
-----------------------
 a
(1 row)

regress=# SELECT find_schema_for_value('testtab','searchval','eggs');
 find_schema_for_value 
-----------------------
 b
(1 row)

regress=# SELECT find_schema_for_value('testtab','searchval','bones');
 find_schema_for_value 
-----------------------

(1 row)

ところで、必要に応じて、継承なしでテーブル定義を再利用することができます。一般的な複合データ型を使用します。

CREATE TYPE public.testtab AS ( searchval text );
CREATE TABLE a.testtab OF public.testtab;
CREATE TABLE b.testtab OF public.testtab;

この場合、それらは同じデータ型を共有しますが、データは共有しません。またはまたは経由LIKE

CREATE TABLE public.testtab ( searchval text );
CREATE TABLE a.testtab (LIKE public.testtab);
CREATE TABLE b.testtab (LIKE public.testtab);

その場合、それらは作成後に互いに完全に接続されていません。

于 2012-10-16T01:51:18.350 に答える