要忽略 PostgreSQL 的 BEFORE TRIGGER 中的结果?

To ignore result in BEFORE TRIGGER of PostgreSQL?

这个线程是这个 的一部分挑战,我正在通过 BEFORE TRIGGER 为其中的一部分寻找更好的解决方案。 我只想启动一个触发器来转换为正确的括号。 我在想我是否应该 return 来自触发器 NULL 或触发器之前的其他内容。

代码

CREATE OR REPLACE FUNCTION insbef_events_function() 
    RETURNS TRIGGER AS 
$func$
DECLARE
    m int[]; 
BEGIN
   FOREACH m SLICE 1 IN ARRAY TG_ARGV[0]::int[]
   LOOP
      INSERT INTO events (measurement_id, event_index_start, event_index_end) 
      SELECT NEW.measurement_id, m[1], m[2];  -- Postgres array starts with 1 !
   END LOOP;

      -- do something with _result ...

RETURN NULL; -- result ignored since this is an BEFORE trigger TODO right?
END 
$func$ LANGUAGE plpgsql;

我用函数

CREATE OR REPLACE FUNCTION f_create_my_trigger_events(_arg1 int, _arg2 text, _arg3 text)
  RETURNS void AS
$func$
BEGIN

EXECUTE format($$
    DROP TRIGGER IF EXISTS insbef_ids ON events
    CREATE TRIGGER insbef_ids
    BEFORE INSERT ON events
    FOR EACH ROW EXECUTE PROCEDURE insbef_events_function(%1$L)$$
    , translate(_arg2, '[]', '{}'), translate(_arg3, '[]', '{}')
);

END
$func$ LANGUAGE plpgsql;

我不确定这一行:RETURN NULL; -- result ignored since this is anBEFOREtrigger TODO right?,因为我认为在 AFTER 触发器中是这种情况,但在触发器之前不是。
我只想启动一个触发器来转换正确的括号。

测试命令 sudo -u postgres psql detector -c "SELECT f_create_my_trigger_events(1,'[112]','[113]');" 出现以下错误,因为我认为 returning -thing 的误解。

LINE 3:     CREATE TRIGGER insbef_ids
            ^
QUERY:  
    DROP TRIGGER IF EXISTS insbef_ids ON events
    CREATE TRIGGER insbef_ids
    BEFORE INSERT ON events
    FOR EACH ROW EXECUTE PROCEDURE insbef_events_function('{112}')
CONTEXT:  PL/pgSQL function f_create_my_trigger_events(integer,text,text) line 4 at EXECUTE statement

如何在 PostgreSQL 9.4 中管理 BEFORE 触发器?

首先,您需要在BEFORE触发器中传递行变量。传递 NULL 取消对行的操作:

CREATE OR REPLACE FUNCTION insbef_events_function() 
  RETURNS TRIGGER AS 
$func$
DECLARE
   m int[]; 
BEGIN
   FOREACH m SLICE 1 IN ARRAY TG_ARGV[0]::int[]
   LOOP
      INSERT INTO events (measurement_id, event_index_start, event_index_end) 
      SELECT NEW.measurement_id, m[1], m[2];  -- Postgres array subscripts start with 1
   END LOOP;

      -- do something with _result ...

   <b>RETURN NEW;  -- NULL would cancel operation in BEFORE trigger!</b>
END 
$func$ LANGUAGE plpgsql;

我演示了 RETRUN NULLAFTER 触发器中的用法 in my previous answer. You can't do the same for a BEFORE trigger. The manual:

Row-level triggers fired BEFORE can return null to signal the trigger manager to skip the rest of the operation for this row (i.e., subsequent triggers are not fired, and the INSERT/UPDATE/DELETE does not occur for this row). If a nonnull value is returned then the operation proceeds with that row value.

还有更多。阅读手册。

但是由于您现在传递的是两个一维数组而不是一个二维数组,您需要调整触发逻辑:

CREATE OR REPLACE FUNCTION insbef_events_function() 
    LANGUAGE plpgsql RETURNS TRIGGER AS 
$func$
DECLARE
   a1 int[] := TG_ARGV[1]::int[];
   a2 int[] := TG_ARGV[2]::int[];
BEGIN
   FOR i in array_lower(a1, 1) .. array_upper(a1, 1)
   LOOP
      INSERT INTO events (measurement_id, event_index_start, event_index_end) 
      SELECT NEW.measurement_id  -- or TG_ARGV[0]::int instead?
           , a1[i], a2[i];
   END LOOP;

   RETURN NEW;  -- NULL would cancel operation in BEFORE trigger!
END 
$func$;

您有责任确保两个数组的元素数量相同。
改变触发器的函数现在看起来像这样:

CREATE OR REPLACE FUNCTION f_create_my_trigger_events(_arg1 int, _arg2 text, _arg3 text)
  LANGUAGE plpgsql RETURNS void AS
$func$
BEGIN
   EXECUTE format(
    $$DROP TRIGGER IF EXISTS insbef_ids ON measurements; -- on measurements ..
      CREATE TRIGGER insbef_ids
      BEFORE INSERT ON measurements  -- .. according to previous posts!!
      FOR EACH ROW EXECUTE PROCEDURE insbef_events_function(%s, %L, %L)$$
    , _arg1
    , translate(_arg2, '[]', '{}')
    , translate(_arg3, '[]', '{}')
   );
END
$func$;

在使用此高级自动化设计之前,您需要了解 SQL、PL/pgSQL、触发函数和数组处理的基础知识。