我有一个像这样的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;
答案 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}}听起来更合适。