2016-05-31 15 views
0

私のデータベースには、標準のアプリケーションテーブルとバックアップテーブルがあります。例えば。テーブル "従業員"の場合、私は "bak_employee"というテーブルを持っています。 bak_employeeテーブルは、employeeテーブルのバックアップです。私はそれを使ってテスト間で従業員テーブルを復元します。PostgreSQL関数が動的テーブル名から結果セットを返す

私は、私はこのようなテスト中に発生した変更を確認するには、これらの「bak_」テーブルを使用することができます理解したい:これは私に挿入され、更新されたレコードを表示します

SELECT * FROM employee EXCEPT SELECT * FROM bak_employee 

。私は今削除されたレコードを無視します。

ここで、データベース内のすべてのテーブルを調べて、テーブルに変更があるかどうかを確認します。私はこれを関数として行うことを考えていたので、何度も何度も繰り返し呼び出すことができます。これはこれまで私が持っているものです:

CREATE OR REPLACE FUNCTION public.show_diff() 
    RETURNS SETOF diff_tables AS 
$BODY$ 

DECLARE 
    app_tables text; 
BEGIN 

    FOR app_tables IN 
     SELECT table_name 

     FROM information_schema.tables 

     WHERE table_catalog = 'myDatabase' 
      AND table_schema = 'public' 
      AND table_name not like 'bak_%'   -- exclude existing backup tables 
    LOOP 

     -- somehow loop through tables to see what's changed something like: 
     EXECUTE 'SELECT * FROM ' || app_tables || ' EXCEPT SELECT * FROM bak_' || app_tables; 

    END LOOP; 

    RETURN; 
END; 
$BODY$ 
LANGUAGE plpgsql; 

しかし、明らかにこれは私に有用な情報を返しません。どんな助けもありがとう。

+1

、しかし:: 'except'多型パラメータの型であなたにすべての違いを表示しません。 'select * from employee e full outer join bak_employee b on e.id = b.idのように、eはbとは別です 'のようなものが良いでしょう。 –

+0

これは実際には「汎用」関数では実行できません。なぜなら、関数は1つの「物」しか返せないからです。しかし、これらのテーブルは異なる数の列を持ち、結果セットは** all **行に対して同じ数の列を持つ必要があります。動作させることができるのは、行のそれぞれをJSONドキュメントまたはキーとして変更された列を含む 'hstore'として返すことです。 –

答えて

2

同じコールで同じ関数からさまざまなよく知られている行タイプを返すことはできません。安価な修正は、各行タイプをtextにキャストすることです。そのため、共通の戻り値の型があります。

CREATE OR REPLACE FUNCTION public.show_diff() 
    RETURNS SETOF text AS -- text!! 
$func$ 
DECLARE 
    app_table text; 
BEGIN 
    FOR app_table IN 
     SELECT table_name 
     FROM information_schema.tables 
     WHERE table_catalog = 'myDatabase' 
     AND table_schema = 'public' 
     AND table_name NOT LIKE 'bak_%' -- exclude existing backup tables 
    LOOP 
     RETURN NEXT ' '; 
     RETURN NEXT '=== ' || app_table || ' ==='; 
     RETURN QUERY EXECUTE format(
     'SELECT x::text FROM (TABLE %I EXCEPT ALL TABLE %I) x' 
     , app_table, 'bak_' || app_table); 
    END LOOP; 

    RETURN; 
END 
$func$ LANGUAGE plpgsql; 

コール:

SELECT * FROM public.show_diff(); 

私が最初にテストsuggested by @a_horseを持っていましたが、your comment後、私はこのために必要がないことに気づきました。 EXCEPTNULLの値をと等しく、と等しく、のすべてをと示しています。

私はその間、あなたのソリューションをさらに改善し、さらに簡素化しました。 EXCEPT ALLを使用してください:安価で、完全な複製を折りたたむリスクはありません。

TABLEだけで構文糖です。

私は速くする必要があります前に、提案のように、あなたは、列(s)はユニーク(の組み合わせ)にインデックス、JOINを持っている場合:経由でのみ可能重複を見つけますインデックスは実質的に安価でなければならない。

重要な要素は、行タイプがtextx::text)にキャストされています。

あなたも、任意のテーブルのための機能を動作させることはできません - しかし、決して一度に一つ以上:

無関係
+0

恐ろしい!!!!あなたの解決策を愛してください。 SELECTステートメントを少し変更しました:SELECT x :: text FROM(SELECT * FROM%I SELECT * FROM%I)x – Steven

+0

@Steven:そうです、EXCEPTはうまくいきます。それ以上は、まだ:「すべてを除いて」。しかし、join *は速くなるかもしれません。更新を検討してください。 –

関連する問題