我试图在postgresql中创建一个触发器,以便在插入之前自动设置一些字段,但我的每个会话只调用一次计算值的过程而不是每次插入。以下是我试图实现这一目标的方法,
>> create table test (
id varchar(16) unique not null
);
id
>> insert into test DEFAULT VALUES;
ERROR: null value in column "id" violates not-null constraint
正如预期的那样,id
不能是null
。
id
。>> create or replace function set_id() returns trigger language plpgsql as $$
begin
new.id = gen_custom_unique_id();
return new;
end $$;
>> CREATE TRIGGER client_update_trigger BEFORE INSERT ON test FOR EACH ROW EXECUTE PROCEDURE set_id();
gen_custom_unique_id
是另一个自定义函数。
尝试在表格中插入行
>> insert into test DEFAULT VALUES;
INSERT 0 1
>> select id from test;
id
------------------
0_EQOEatMNaXO2a-
(1 row)
..按预期工作。
>> insert into test DEFAULT VALUES;
ERROR: duplicate key value violates unique constraint "test_id_key"
DETAIL: Key (id)=(0_EQOEatMNaXO2a-) already exists.
我的理解是,这应该再次调用过程set_id
并生成一个新的唯一ID,但每次会话只调用set_id
一次。如果我从数据库断开连接并尝试新会话,INSERT
将再次运行。
EXECUTE PROCEDURE set_id();
确实看起来很可疑,因为我们正在调用内联程序。直觉上,我认为它应该是EXECUTE PROCEDURE set_id;
然后触发器应该"调用"在插入每一行之前set_id
,但这不起作用。
如何将EXECUTE PROCEDURE set_id();
变成EXECUTE PROCEDURE lazy(set_id());
之类的内容?
我确定gen_custom_unique_id
工作正常。代码太冗长,与IMO分享无关。为了这个例子,我们可以假设它只返回一个UUID或时间戳。我测试过它按预期工作,这是输出。
>> select * from gen_custom_unique_id();
gen_custom_unique_id
------------------
0_Elu4sdjRxW6s_s
(1 row)
>> select * from gen_custom_unique_id();
gen_custom_unique_id
------------------
0_EluVMKwLjJQP2s
(1 row)
>> select * from gen_custom_unique_id();
gen_custom_unique_id
------------------
0_ElutuejkWhR07N
(1 row)
>> select * from gen_custom_unique_id();
gen_custom_unique_id
------------------
0_ElvHrif6X2pQH-
(1 row)
>> select * from gen_custom_unique_id();
gen_custom_unique_id
------------------
0_ElvgXWgGIMYeHk
(1 row)
此函数会生成类似firebase或simpleflake ID(http://akmanalp.com/simpleflake_presentation/#/)
的内容我做了一些进一步的测试,看起来确实缓存了get_custom_unique_id
或set_id
的输出。
我向get_custom_unique_id
添加了一条NOTICE语句,它仅在触发器第一次调用该函数时打印。
gen_custom_unique_id
>> select * from gen_custom_unique_id();
NOTICE: generating id: 0_Il_GKmrwCwkUJJ
gen_custom_unique_id
------------------
0_Il_GKmrwCwkUJJ
(1 row)
>> select * from gen_custom_unique_id();
NOTICE: generating id: 0_Il_xBXWXvLuwBk
gen_custom_unique_id
------------------
0_Il_xBXWXvLuwBk
(1 row)
>> select * from gen_custom_unique_id();
NOTICE: generating id: 0_IlbKk0ixgnkIdA
gen_custom_unique_id
------------------
0_IlbKk0ixgnkIdA
(1 row)
请注意它如何打印NOTICE: generating id: {generated_id}
。
>> insert into test DEFAULT VALUES;
NOTICE: generating id: 0_IsgcquLRup1KxF
CONTEXT: SQL statement "SELECT gen_custom_unique_id()"
PL/pgSQL function set_id() line 3 at assignment
INSERT 0 1
>> insert into test DEFAULT VALUES;
ERROR: duplicate key value violates unique constraint "test_pkey"
DETAIL: Key (id)=(0_IsgcquLRup1KxF) already exists.
来自gen_custom_unique_id
的通知仅在第一次调用时打印,因此每次都不会调用它。
答案 0 :(得分:0)
有关您的信息:将(调用a)自定义函数作为列的默认值连接,可以像在postgres中实现连续符的方式一样。它不需要触发器。我将clock_timestamp()演示为序列生成函数:
CREATE TABLE omg
-- NOTE: clock_timestamp is volatile by nature,
-- which means that the query-optimiser cannot presume
-- that calling it twice would result in the same result
-- (THUS: the function is called anytime a value is needed)
( id timestamp NOT NULL PRIMARY KEY DEFAULT clock_timestamp()
, payload text
);
INSERT INTO omg(payload) VALUES ('one' );
INSERT INTO omg(payload) VALUES ('two' );
SELECT * FROM omg;
结果:
CREATE TABLE
INSERT 0 1
INSERT 0 1
id | payload
----------------------------+---------
2015-11-11 15:29:07.330905 | one
2015-11-11 15:29:07.338803 | two
(2 rows)