如何检查 Postgres 触发器函数中是否存在旧列

How to check if OLD column exist in Postgres Trigger Function

我想创建一个已删除的日志并从旧行列插入数据。问题是每个 table 的列都不相同,一些 tables 只有 transaction_date 而其他 table 只有 created_at。所以我想检查 transaction_date 是否只使用它,否则使用 created_at 列。我尝试使用 coalesce 函数,但仍然 return:

ERROR: record "old" has no field "transaction_date" CONTEXT: SQL statement "INSERT INTO "public"."delete_logs" ("table", "date") VALUES (TG_TABLE_NAME, coalesce(OLD.transaction_date, coalesce(OLD.created_at, now())))" PL/pgSQL function delete_table() line 2 at SQL statement

这是我的函数:

CREATE OR REPLACE FUNCTION delete_table() RETURNS trigger AS
$$BEGIN
INSERT INTO "public"."deleted_logs" ("table", "created_at") VALUES (TG_TABLE_NAME, coalesce(OLD.transaction_date, coalesce(OLD.created_at, now())));

   RETURN OLD;
END;$$ LANGUAGE plpgsql;


CREATE TRIGGER "testDelete" AFTER DELETE ON "exampletable" FOR EACH ROW EXECUTE PROCEDURE "delete_table"();

其实我想为每个table创建一个函数,但是我觉得以后很难更新这个函数,所以我需要为所有[=24=创建一个函数]s.

So I want to check if transaction_date just use it, otherwise use created_at column.

您可以通过将行转换为 json:

来避免您看到的异常
CREATE OR REPLACE FUNCTION log_ts_after_delete()
  RETURNS trigger
  LANGUAGE plpgsql AS
$func$
BEGIN
   INSERT INTO public.deleted_logs
          (table_name   , created_at)  -- "table" is a reserved word
   VALUES (TG_TABLE_NAME, COALESCE(to_json(OLD)->>'transaction_date', to_json(OLD)->>'created_at')::timestamptz);


   RETURN NULL;  -- not used in AFTER trugger
END
$func$;

我的回答假定 transaction_date 定义为 NOT NULL。否则,表达式默认为 created_at。可能不是你想要的。

JSON 没有 SQL 严格。对不存在的 JSON 键的引用导致 NULL 而不是对不存在的 table 列的引用的异常。所以 COALESCE 就可以了。

相关:

  • How to set value of composite variable field using dynamic SQL

如果行很宽,只转换一次 JSON 并将其保存到变量中,或者在子查询或 CTE 中进行转换可能更便宜。

相关:

如果 table 从不切换有问题的列,则在触发器定义中传递参数会 便宜得多 。 您发现(在创建触发器时)一次 具有:

SELECT attname
FROM   pg_attribute
WHERE  attrelid = 'public.exampletable'::regclass
AND    attname IN ('transaction_date', 'created_at')
AND    NOT attisdropped 
ORDER  BY attname DESC

此returns 'transaction_date' 如果table中存在这样的列,else 'created_at',else NULL(无行)。相关:

  • PostgreSQL rename a column only if it exists

每种类型的触发器都有一个单独的触发器功能仍然是最便宜的。只有两个功能而不是一个。如果经常触发触发器,我会做 that.

如果您可以,则避免异常处理。 The manual:

Tip

A block containing an EXCEPTION clause is significantly more expensive to enter and exit than a block without one. Therefore, don't use EXCEPTION without need.