触发每次更新或插入

时间:2014-08-27 12:55:02

标签: sql postgresql

我想创建每次更改任何列时触发的触发器 - 无论是新更新还是新插入。我创造了这样的东西:

CREATE TRIGGER textsearch
  BEFORE INSERT OR UPDATE
  ON table
  FOR EACH ROW
  EXECUTE PROCEDURE trigger();

和trigger()函数的主体是:

BEGIN
   NEW.ts := (
    SELECT   COALESCE(a::text,'') || ' ' ||
             COALESCE(b::int,'')  || ' ' ||
             COALESCE(c::text,'') || ' ' ||
             COALESCE(d::int, '') || ' ' ||
             COALESCE(e::text,'')
    FROM    table
    WHERE   table.id = new.id);

   RETURN NEW;

END

我希望很清楚我想做什么。

我的问题是触发器仅在更新时触发,而不是在插入时触发。我猜这不行,因为我有INSFORE INSERT或UPDATE,但是如果我把它改成AFTER INSERT或UPDATE那么它既不适用于INSERT也不适用于UPDATE。

3 个答案:

答案 0 :(得分:1)

您需要直接使用NEW记录:

BEGIN
   NEW.ts := concat_ws(' ', NEW.a::text, NEW.b::TEXT, NEW.c::TEXT);
   RETURN NEW;
END;

concat_ws优于||的优势在于concat_ws会以不同的方式处理NULL值。 'foo'||NULL的结果将产生NULL,这很可能不是您想要的。 concat_ws将使用空字符串NULL值。

答案 1 :(得分:0)

它不起作用,因为你在函数内部调用SELECT。

当它运行BEFORE INSERT时,没有要选择的行,是吗?

实际上,BEFORE UPDATE无论如何你都会看到该行的“旧”版本,不是吗?

只需直接使用字段:NEW.a等,而不是选择。


作为编辑 - 这是一个显示触发器功能可以看到的示例。正如您在BEFORE触发器中所期望的那样,这是非常的。

BEGIN;

CREATE TABLE tt (i int, t text, PRIMARY KEY (i));

CREATE FUNCTION trigfn() RETURNS TRIGGER AS $$
DECLARE
    sv text;
BEGIN
    SELECT t INTO sv FROM tt WHERE i = NEW.i;
    RAISE NOTICE 'new value = %, selected value = %', NEW.t, sv;
    RETURN NEW;
END;
$$ LANGUAGE plpgsql;

CREATE TRIGGER trigtest BEFORE INSERT OR UPDATE ON tt FOR EACH ROW EXECUTE PROCEDURE trigfn();

INSERT INTO tt VALUES (1,'a1');
UPDATE tt SET t = 'a2' WHERE i = 1;

ROLLBACK;

答案 2 :(得分:0)

当你转换b :: int时,在你的COALESCE语句中

我必须改变你的coalesce来改为使用整数占位符。正如a_horse_with_no_name所提到的,这可能会以null值结束,但您可以看到如何运行您的特定代码示例。我收录了#34; RAISE NOTICE"这些行仅用于调试目的。

根据您提供的信息,以下内容适用于我:

CREATE TABLE my_table (id SERIAL NOT NULL,a TEXT,b INTEGER,c TEXT,d INTEGER,e TEXT);

CREATE OR REPLACE FUNCTION my_triggered_procedure() RETURNS trigger AS $$
BEGIN
    if(TG_OP = 'UPDATE' OR TG_OP = 'INSERT') THEN
        NEW.ts := (SELECT COALESCE(a::text,'') || ' ' ||
                          COALESCE(b::int,0) || ' ' || 
                          COALESCE(c::text,'') || ' ' || 
                          COALESCE(d::int, 0) || ' ' || 
                          COALESCE(e::text,'') 
                   FROM my_table 
                   WHERE id=NEW.id);         
        RAISE NOTICE 'INSERT OR UPDATE with new ts = %',NEW.ts;  
        RETURN NEW;
    ELSIF (TG_OP = 'DELETE') THEN
        OLD.ts := ' ';        
        RAISE NOTICE 'DELETED old id: %',OLD.id;
        RETURN OLD;  
    END IF;
END;
$$ LANGUAGE plpgsql;

CREATE TRIGGER text_search 
 AFTER INSERT OR UPDATE OR DELETE 
 ON my_table
 FOR EACH ROW
 EXECUTE PROCEDURE my_triggered_procedure();

INSERT INTO my_table (a,b,c,d,e) VALUES('text11',12,'text21',3,'text4');
>NOTICE:  INSERT OR UPDATE with new ts = text11 12 text21 3 text4
>INSERT 0 1

DELETE FROM my_table WHERE id=24;
>NOTICE:  DELETED ID = 24
>DELETE 1

PostgreSQL::Trigger Procedures