2

Postgres 9.1 の plpgsql でトリガーを作成しています。指定されたアクションを監査テーブルに記録できるように、UPDATE の SET 句で発行された列名を取得できる必要があります。Postgres ドキュメントの例は単純で、私のニーズには不十分です。私は何日もインターネットを検索しましたが、ここでやりたいことを達成しようとする他の例を見つけることができません.

私はこれをすぐに解決するためにタイトなスケジュールを組んでいます。私は Tcl を知らないので、現時点では pl/Tcl は問題外です。pl/Perl は機能するかもしれませんが、どこから始めればよいかわかりません。また、移植性とメンテナンスのために、可能であれば pl/pgsql でこれを達成する方法を見つけたかったのです。誰かがこれに対する pl/Perl ソリューションを推奨できれば、私は感謝します。

監査される対象テーブルのテーブル構造は次のとおりです。

注: レコード テーブルには他にも多くの列がありますが、簡単にするためにここには記載していません。ただし、トリガーは、行内の任意の列への変更を記録できる必要があります。

CREATE TABLE record (
   record_id    integer NOT NULL PRIMARY KEY,
   lastname     text,
   frstname     text,
   dob          date,
   created      timestamp default NOW(),
   created_by   integer,
   inactive     boolean default false
);
create sequence record_record_id_seq;
alter table record alter record_id set default nextval('record_record_id_seq');

これが私の監査テーブルです:

CREATE TABLE record_audit (
   id                integer NOT NULL PRIMARY KEY,
   operation         char(1) NOT NULL, -- U, I or D
   source_column     text,
   source_id         integer,
   old_value         text,
   new_value         text,
   created_date      timestamp default now(),
   created_by        integer
);
create sequence record_audit_id_seq;
alter table record_audit alter id set default nextval('record_audit_id_seq');

私の目標は、更新されたターゲット record_id (source_id) と更新された列 (source_column) だけでなく、old_value と new_value の詳細も記録する record_audit テーブルのレコード テーブルに INSERTS と UPDATE を記録することです桁。

列の値は、テキストの種類に CAST() する必要があることを理解しています。NEW と OLD にアクセスすることで old_value と new_value にアクセスできると思いますが、UPDATE クエリの SET 句で使用される列名を取得する方法がわかりません。SET 句で指定されたすべての列の record_audit テーブルに新しいレコードを追加するトリガーが必要です。レコードは単純に非アクティブ = 't' に更新されるため、DELETE アクションはありません (したがって、監査テーブルに記録されます)。

これまでの私のトリガーは次のとおりです(明らかに不完全です)。許してください、私は行くにつれてpl/pgsqlを学んでいます。

-- Trigger function for record_audit table
CREATE OR REPLACE FUNCTION audit_record() RETURNS TRIGER AS $$
   DECLARE
      insert_table  text;
      ref_col       text; --how to get the referenced column name??

   BEGIN
      --
      -- Create a new row in record_audit depending on the operation (TG_OP)
      --
      IF (TG_OP = 'INSERT') THEN

         -- old_value and new_value are meaningless for INSERTs. Just record the new ID.
         INSERT INTO record_audit 
            (operation,source_id,created_by) 
         VALUES
            ('I', NEW.record_id, NEW.created_by);


      ELSIF (TG_OP = 'UPDATE') THEN

         FOR i in 1 .. TG_ARGV[0] LOOP
            ref_col := TG_ARGV[i].column; -- I know .column doesn't exist but what to use?

            INSERT INTO record_audit 
               (operation, source_column, source_id, old_value, new_value, created_by) 
            VALUES 
               ('U', ref_col, NEW.record_id, OLD.ref_col, NEW.ref_col, NEW.created_by); 
         END LOOP;

      END IF;
      RETURN NULL; -- result is ignored anyway since this is an AFTER trigger
   END;
$$ LANGUAGE plpgsql;

CREATE TRIGGER record_audit_trig
AFTER INSERT OR UPDATE on record
   FOR EACH ROW EXECUTE PROCEDURE audit_record();

この長く曲がりくねった質問を読んでくれてありがとう!

4

1 に答える 1

1

この情報を取得することはできません-PLレベルではありません-おそらくCで可能です。

十分な解決策は、レコードNEWおよびOLDの変更されたフィールドに基づいています。システムテーブルからフィールドのリストを取得できます〜トリガーに結合されたテーブルに関連しています。

于 2013-02-27T16:09:20.073 に答える