【问题标题】:cannot return non-composite value from function returning composite type无法从返回复合类型的函数返回非复合值
【发布时间】:2021-05-05 06:39:39
【问题描述】:

我有 2 个名为票证和票证更新的表

  • 工单(工单ID、问题、状态(设置为打开或关闭)、优先级、记录时间、客户ID、产品ID)

  • ticketupdate(ticketupdateID、updatemessage、updatetime、ticketID、staffID)

我想创建一个触发器,所以当我将值插入ticketupdate 表时,它会检查ticket 表的状态以查看它是打开还是关闭。如果它已关闭,那么它会阻止我插入值。

我创建了一个触发器和函数如下:

create or replace function check_status()
returns trigger as $BODY$
BEGIN
  return (select status from ticket where new.ticketID = ticket.ticketID);
  if ticket.status = 'open' then
    insert into ticketupdate values (ticketupdateid, update_message,    
current_timestamp, ticketID, staffID);
  else
    raise exception 'Status of the ticket is closed, no further action necessary.';
  end if;
end;
$BODY$ 
LANGUAGE plpgsql;

create trigger update_ticket
after update on ticket
for each row
execute procedure check_status();

但是,当我在其中插入值时,我收到一条错误消息:无法从返回复合类型的函数返回非复合值

【问题讨论】:

    标签: postgresql


    【解决方案1】:

    触发函数需要返回newold 记录。您似乎将return 语句与赋值混淆了。

    因为触发器是在ticket 表上定义的,所以不需要运行选择来访问status 列的值。您可以通过new记录直接访问。

    在 INSERT 语句中列出所有目标列也是一种很好的编码习惯。

    我不清楚 INSERT 的值应该来自哪里,我已经用?? 标记了缺失的部分。假设ticketupdateid 是一个标识(或序列)列,您可能不应该为它提供值。但是您仍然需要 update_messagestaffid 的值才能来自某个地方。

    所以你可能正在寻找类似的东西:

    create or replace function check_status()
      returns trigger 
    as 
    $BODY$
    begin
      if new.status = 'open' then
        insert into ticketupdate (updatemessage, updatetime, ticketid, staffid)
        values (??, current_timestamp, new.ticketid, ??);
      else
        raise exception 'Status of the ticket is closed, no further action necessary.';
      end if;
      
      return new;  -<< required for a trigger
    end;
    $BODY$ 
    LANGUAGE plpgsql;
    

    【讨论】:

      【解决方案2】:

      @a_horse_with_no_name 表示迄今为止最常见的禁止 DML 语句的用法。在某些情况下,问题在于它中止了整个事务。但是 Postgres 提供了一个替代方案。您可以返回 NULL 以取消该特定行,但其他人继续。来自文档:

      触发器函数必须返回 NULL 或记录/行值 准确地具有触发触发器的表的结构。

      BEFORE 触发的行级触发器可以返回 null 来表示触发器 经理跳过该行的其余操作(即, 随后的触发器不会被触发,并且 INSERT/UPDATE/DELETE 会 此行不会出现)。

      也许:

      create or replace function check_status()
        returns trigger 
       language plpgsql
      as $$
      begin
         if old.status = 'closed' then
            raise log 'Ticket % is closed, no further action allowed.',old.ticketid;
            return null; 
         end if; 
         
         insert into ticketupdate (updatemessage, updatetime, ticketid, staffid)
              values (??, current_timestamp, new.ticketid, ??);
      
        return new;  
      end;
      $$; 
        
      create trigger update_ticket
      before update on ticket           --- must be BEFORE
      for each row
      execute procedure check_status();
      

      NOTICE 生成日志:重要的是您在此处生成一条消息,以某种方式指示未执行更新。您可以使用“拒绝”消息写入ticketupdate 表。不提供易于访问的消息只会产生混淆,看起来很难找到错误,而实际上它是所需的操作过程。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2020-08-03
        • 2012-08-10
        • 2011-05-16
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2020-04-25
        • 1970-01-01
        相关资源
        最近更新 更多