web-dev-qa-db-ja.com

PostgreSQLのスキーマ内のすべてのテーブルから選択するには

スキーマ内のすべてのテーブルから選択することは可能ですか?すべてのテーブル名を

select table_name from information_schema.tables

しかし、それを使用してクエリを実行することはできません。

7
Stat-R

テーブル名がわからない場合(つまり、いくつかの変数またはサブクエリから)、「通常の」クエリを記述できないため、直接実行することはできません。ただし、このために動的SQLステートメントを作成して実行できます。たとえば、すべてのテーブルの列 'name'が必要な場合は、次のようにすることができます( PL/pgSQL関数 内で)。

_FOR i IN SELECT table_name 
           FROM information_schema.tables 
          WHERE table_schema = 'your_desired_schema'
LOOP
    sql_string := sql_string || format($$
        -- some whitespace is mandatory here
        UNION
        SELECT name FROM %I
    $$,
    i.table_name);
END LOOP;

EXECUTE sql_string;
_

ただし、この形式では機能しません。変数に入力しない限り、SELECTplpqsqlを実行できないためです。このための一時テーブルを作成するか、(他のFORループで)結果をループするか、またはUNIONを使用せずに、必要に応じてすべての反復で単に戻ります。

そしてもちろん、これはすべてのテーブルから単一の列(または複数の、ただし常に同じ名前とタイプを持つ)を選択することを前提としています。すべてのテーブルのすべてのデータが必要な場合、テーブルは同じ構造(同じ列型、同じ順序、同じ名前)でなければなりません。

ノート:

  • format()関数はバージョン9.1で導入されました
  • シンプルにするために、PL/pgSQLブロックの必須要素をいくつか省略しました
  • 以前のバージョンはDOブロックの使用について言及していました。 別の答え で指摘されているように、行の戻り値としてSELECTを単純に使用することはできないという問題があります。
4
dezso

OK、本当に遅いですが、同じ問題を解決するために解決し、FUNCTIONが機能しなかったため、DOを使用して特定のスキーマの下のすべてのテーブルのすべての行を返すことができました。 DOを使用しても何も返されなかったので、ここに私のFUNCTIONを示します。

CREATE OR REPLACE FUNCTION union_all_tables()
  RETURNS TABLE
          (
            id        integer,
            full_name varchar(100),
            col3      varchar(200),
            col4      numeric,
            col5      char,
            version   bigint
          ) AS
$$
DECLARE
  dynamic_query text = '';
  r_row         record;
BEGIN
  FOR r_row IN SELECT table_schema || '.' || table_name qualified_table_name
               FROM information_schema.tables
               WHERE table_schema = 'staging'
                 AND table_name LIKE '%_postfix'
    LOOP
      dynamic_query := dynamic_query || format('UNION SELECT ' ||
                                               'id, ' ||
                                               'full_name, ' ||
                                               'col3, ' ||
                                               'col4, ' ||
                                               'col5, ' ||
                                               'version ' ||
                                               'FROM %s ', r_row.qualified_table_name) || E'\n'; -- adding new line for pretty print, it is not necessary
    END LOOP;

  -- before we execute the query, we need to remove first "UNION " from the string
  dynamic_query := SUBSTRING(dynamic_query, 7) || ';';

  -- printing the statement as a notice so you know that the statement is in a good format, 
  -- or you can copy paste it and try it in the console to know if that statement is working or not. 
  RAISE NOTICE 'Union all tables in staging, executing statement: %', dynamic_query;
  RETURN QUERY EXECUTE dynamic_query;
END;
$$
  LANGUAGE plpgsql;

AND table_name LIKE '%_postfix'をここに追加したのは、命名規則があり、そのための頭痛を軽減したい場合は、ここに追加します。不要な場合は削除します。また、UNIONを作成する場合は、すべてのテーブルをフォローする必要があります。同じ構造、必要な共通の列を選択しない場合(これは私のソリューションではこれが私のケースです)、それ以外の場合、すべての列が必要な場合は、さらに複雑なスクリプトが必要です。

このソリューションは、PostgreSQL 10および11で私に役立ちます。

1
Al-Mothafar

これは、上記のアプローチに基づく回避策です。

 DECLARE
 tables CURSOR FOR SELECT * 
      FROM information_schema.tables 
      WHERE table_schema = 'public' 
      ORDER BY "table_name" ASC
      LIMIT ((SELECT count(*)
          FROM information_schema.tables
          WHERE table_schema = 'public')-1);
          --Because the following prepared string starts with a 'UNION ALL',
          --this completes the query string with a select starting with the last table
          sql_string text := 'SELECT field1, field7, field8, "source" FROM ' || quote_IDENT((SELECT "table_name" FROM information_schema.tables WHERE table_schema = 'public' ORDER BY "table_name" DESC LIMIT 1));

 BEGIN

 FOR table_record IN tables LOOP
     sql_string := sql_string || '
         UNION ALL
         SELECT columns FROM ' || quote_IDENT(table_record."table_name");
 END LOOP;

 sql_string := sql_string||';';
 RETURN sql_string;
 --EXECUTE sql_string;

 END;
0
Icefelix