函数在触发器内返回错误值

时间:2016-08-30 09:29:56

标签: sql postgresql plpgsql database-trigger

我有两个返回好价值的函数。但是当我在触发器中调用这些函数时,它们总是返回0而不是良好的值。

这些函数的返回类型是real。直接和戏剧性的结果是触发器在调用时会在表中插入错误的值。

功能:

create or replace function get_remaining_hour(id_user_v integer,id_absence_v_type integer,id_year_v integer) returns real as
$BODY$
BEGIN
    return (select sum(number_hour) 
            from remaining_absence_day 
            where id_user= $1 
              and id_absence_type=$2 
              and id_year=$3 );
END;
$BODY$
LANGUAGE 'plpgsql' ;

触发功能(为测试而修改!):

create  OR REPLACE  function update_absence() returns TRIGGER  AS
$BODY$
DECLARE
  old_number_hour real;
BEGIN
  old_number_hour:=get_remaining_hour(3,2,8);
  insert into debugging(col,val) values('old_number_hour', old_number_hour);
  return null;
END;
$BODY$
LANGUAGE 'plpgsql' ;

触发器定义:

drop trigger if exists update_absence on absence;
CREATE  TRIGGER update_absence
    after update of type,duration_hour,duration_day on absence
    for each ROW
    execute procedure update_absence();

1 个答案:

答案 0 :(得分:1)

提供的代码应该有效。

特别奇怪的是,您会看到 0 。如果在remaining_absence_day中找不到匹配的行,您会看到NULL,而不是0。但是如果你在相同的环境中调用具有相同参数的函数,你应该看到相同的结果。

我能想到的其余可能解释:与架构搜索路径混淆。例如:您在另一个模式中有函数get_remaining_hour()或表remaining_absence_day的第二个实例。并且您使用search_path的不同设置调用该函数。 你是否在同一个会话中进行了比较?

或者,因为您使用了AFTER触发器:表absence上可能有其他触发器修改了表remaining_absence_day,这些触发器被触发< em>在你的触发器之前。

我所做的所有其他修改都具有美观性或简化性

CREATE OR REPLACE FUNCTION get_remaining_hour(id_user_v int
                                            , id_absence_v_type int
                                            , id_year_v int)
  RETURNS real AS
$func$
BEGIN
   RETURN (
   SELECT sum(number_hour) 
   FROM   remaining_absence_day  -- referencing the right table? see search_path
   WHERE  id_user         = $1 
   AND    id_absence_type = $2 
   AND    id_year         = $3
   );
END
$func$  LANGUAGE plpgsql STABLE;  -- don't quote the language name

CREATE OR REPLACE FUNCTION update_absence()
  RETURNS TRIGGER AS
$func$
BEGIN   
   INSERT INTO debugging(col, val)
   VALUES('old_number_hour', get_remaining_hour(3,2,8));  -- hard coded only for testing?
   RETURN null;  -- only good for AFTER trigger
END
$func$  LANGUAGE plpgsql;

DROP TRIGGER IF EXISTS update_absence ON absence;
CREATE TRIGGER update_absence
AFTER UPDATE OF type, duration_hour, duration_day ON absence
FOR EACH ROW EXECUTE PROCEDURE update_absence();