【问题标题】:Get access to OLD.myLoopVariable / NEW.myLoopVariable in a plpgsql trigger function?在 plpgsql 触发函数中访问 OLD.myLoopVariable / NEW.myLoopVariable?
【发布时间】:2017-07-28 07:56:22
【问题描述】:

我尝试访问作为表列名的循环变量,以获取每列的旧数据和新数据。

CREATE FUNCTION my_function() RETURNS TRIGGER AS $emp_stamp$
DECLARE
  current_column_name text;
BEGIN
  FOR current_column_name IN
    SELECT column_name 
    FROM information_schema.Columns 
    WHERE table_schema = TG_TABLE_SCHEMA AND table_name = TG_TABLE_NAME 
    LOOP
      IF (OLD."current_column_name" <> NEW."current_column_name")
      then ...
      END IF;
    END LOOP;
  RETURN NEW;
END;
$emp_stamp$ LANGUAGE plpgsql;

CREATE TRIGGER my_trigger
AFTER UPDATE ON my_table FOR EACH ROW
EXECUTE PROCEDURE my_function();

我还有一个错误:ERROR: record "old" has no field "current_column_name"
我尝试不带引号 (""),但得到了相同的结果。

如何访问新旧列数据?
我需要保存所有更改的数据,例如包含以下字段的历史记录:column_nameold_valuenew_value

【问题讨论】:

标签: database postgresql triggers plpgsql


【解决方案1】:

您不能在纯 SQL 中参数化标识符。为此,您需要 动态 SQL,即:动态构建查询字符串,然后执行它,这可能很麻烦且容易出错。对于您的情况,有一个更简单的替代方案,特别是因为无论如何您都需要将所有列转换为通用数据类型,自然选择text

也不能循环通过记录或行类型的字段。这就是您目前从信息架构中读取元数据以遍历列的原因,但您也可以这样做更简单。

使用扩展名 hstore 及其工具。每个数据库安装一次:

使用明显的函数hstore()将一行转换为hstore

hstore(OLD)

它返回一个类型hstore,这是一个键/值存储,所有值都转换为text. Now you have various options. Probably simplest: unnest witheach()`并加入:

CREATE FUNCTION my_function()
  RETURNS TRIGGER AS
$func$
DECLARE
   _col text;
   _old_val text;
   _new_val text;
BEGIN
   FOR       _col, _old_val, _new_val
      SELECT key , o.value , n.value
      FROM   each(hstore(OLD)) o  -- (key, value)
      JOIN   each(hstore(NEW)) n USING (key)
      WHERE  o.value IS DISTINCT FROM n.value  -- only changed columns
   LOOP
     -- do something
   END LOOP;

   RETURN NEW;
END
$func$  LANGUAGE plpgsql;

如果您只想将更改的列插入到审计表中,请将其设为单个 SQL 命令,并且完全不循环:

CREATE FUNCTION my_function()
  RETURNS TRIGGER AS
$func$
BEGIN
   INSERT INTO audit_table
         (tbl_schema     , tbl          , col , oldval , newval)
   SELECT TG_TABLE_SCHEMA, TG_TABLE_NAME, key , o.value, n.value
   FROM   each(hstore(OLD)) o  -- (key, value)
   JOIN   each(hstore(NEW)) n USING (key)
   WHERE  o.value IS DISTINCT FROM n.value;

   RETURN NEW;
END
$func$  LANGUAGE plpgsql;

或者您可以使用%# hstore(OLD)hstore 转换为二维键/值数组,并按照此处的说明循环:


对于更复杂的需求,有审计解决方案,like a_horse commented.

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-02-26
    • 1970-01-01
    • 2013-02-03
    • 2016-12-26
    • 2019-08-10
    • 1970-01-01
    相关资源
    最近更新 更多