POSTGRESQL pl / pgsql触发器函数在插入时返回null

时间:2012-01-27 11:26:26

标签: sql postgresql triggers insert plpgsql

我有一个像这样的pg表:

CREATE TABLE order_status_history (
order_id integer NOT NULL,
status character varying NOT NULL,
sequence integer DEFAULT 1 NOT NULL,
date_status timestamp with time zone DEFAULT now() NOT NULL,
record_state character varying(12) DEFAULT 'ACTIVE'::character varying NOT NULL
);

在order_id和序列上使用复合PK。 从本质上讲,状态列是从1开始的每个order_id的自动增量值。因此,如果order_id 2已经有两行,则序列将为1和2,对于新行,序列应为3。 我试图在插入之前使用触发器来实现此行为,但是当我尝试为新的order_id插入第一行时(即触发器不必在插入之前更改行),我收到错误为PG。说它不能将NULL插入序列中。我无法看到我的触发器函数将如何返回NULL,但我的pl / sql并不是很好所以我确定它很简单......触发函数如下,谢谢。

DECLARE
    seq_no INTEGER;

BEGIN
    SELECT INTO seq_no MAX(sequence) FROM rar.order_status_history WHERE order_id = NEW.order_id;
    IF FOUND THEN 
        NEW.sequence := seq_no + 1;
    END IF;

    RETURN NEW;
END;

2 个答案:

答案 0 :(得分:2)

如果order_status_history中没有该order_id,则MAX(sequence)将为空。使用COALESCE(MAX(sequence),0)将其设为默认值为1。

你可以写一下:

NEW.sequence := (SELECT COALESCE(MAX(sequence),0) FROM /* etc.. */) + 1;

在执行此操作之前,您确实应该以独占模式锁定订单行,以允许此操作同时插入同一订单的历史记录中的多个事务。那就是:

SELECT 1 FROM orders WHERE orders.order_id = NEW.order_id FOR UPDATE;

答案 1 :(得分:1)

max(sequence)始终为FOUND,但如果没有数据,则NULL可能为NEW.sequence := seq_no + 1。在这种情况下,您的NULL仍然会IF seq_no IS NOT NULL。 {{1}}听起来更合适。