web-dev-qa-db-ja.com

複数のテーブルからデータをループして選択する関数

私はPostgresを初めて使用し、同じ構造の複数のテーブルを持つデータベースを持っています。特定の基準に一致する各テーブルからデータを選択する必要があります。

一連のUNIONクエリを使用してこれを行うことができますが、検索する必要があるテーブルの数は時間の経過とともに変化する可能性があるため、そのようにハードコーディングしたくありません。特定のテーブル(共通の命名規則があります)をループしてレコードのテーブルを返す関数を開発しようとしていますが、関数をクエリしても結果が得られません。機能コードは以下のとおりです。

CREATE OR REPLACE FUNCTION public.internalid_formaltable_name_lookup()
  RETURNS TABLE(natural_id text, name text, natural_id_numeric text) AS
$BODY$
DECLARE
    formal_table text;
begin
  FOR formal_table IN
    select table_name from information_schema.tables
    where table_schema = 'public' and table_name like 'formaltable%'
  LOOP
    EXECUTE 'SELECT natural_id, name, natural_id_numeric
             FROM ' || formal_table || 
           ' WHERE natural_id_numeric IN (
                select natural_id_numeric from internal_idlookup
                where internal_id = ''7166571'')';
    RETURN NEXT;
 END LOOP;
 Return;
END;
$BODY$
  LANGUAGE plpgsql;

関数を使用しようとしたときにエラーは発生しませんが、行が返されません。

SELECT * From internalid_formaltable_name_lookup();

私が間違ったところはありますか?

9
user3813773
_CREATE OR REPLACE FUNCTION public.internalid_formaltable_name_lookup()
  RETURNS TABLE(natural_id text, name text, natural_id_numeric text) AS
$func$
DECLARE
   formal_table text;
BEGIN
   FOR formal_table IN
      SELECT quote_ident(table_name)
      FROM   information_schema.tables
      WHERE  table_schema = 'public'
      AND    table_name LIKE 'formaltable%'
   LOOP
      RETURN QUERY EXECUTE
      'SELECT t.natural_id, t.name, t.natural_id_numeric
       FROM   internal_idlookup i 
       JOIN   public.' || formal_table || ' t USING (natural_id_numeric)
       WHERE  i.internal_id = 7166571';   -- assuming internal_id is numeric
   END LOOP;
END
$func$  LANGUAGE plpgsql;
_

主なポイント:

  • _RETURN QUERY EXECUTE_ を使用して、各行のセット
    EXECUTEの後に_RETURN NEXT_が続くと、期待したようにまったく動作しません

  • 識別子をサニタイズする必要があります。ここではquote_ident()を使用しています。または、クエリが非標準の識別子で壊れ、SQLインジェクションが可能になります!

  • col IN (sub-select)をより効率的なJOINに変換しました。

  • これは_a bunch of UNION queries_の使用とは微妙に異なります。重複する行はではなく削除し、実際には _UNION ALL_ のように機能します。

個人的には、これをシステムカタログ_pg_class_に構築したいと思います。詳細:

次に、_pg_class.oid::regclass_を使用して、テーブル名を自動的にエスケープおよびスキーマ修飾します。詳細:

しかし、それは要件の詳細と...味に依存します。

17