我有两张桌子:
CREATE TABLE "user"
(
username character varying(35) NOT NULL,
CONSTRAINT user_pk PRIMARY KEY (username)
)
CREATE TABLE item
(
id serial NOT NULL,
username character varying(35),
user_item_number integer,
item_value character varying(35),
CONSTRAINT item_pk PRIMARY KEY (id),
CONSTRAINT item_fk FOREIGN KEY (username)
REFERENCES "user" (username) MATCH SIMPLE
ON UPDATE NO ACTION ON DELETE NO ACTION,
CONSTRAINT unique_item_username UNIQUE (username, user_item_number)
)
我想为每个user_item_number
分别自动增加username
。下图显示了示例。对于每个username
:( user1
,user2
)user_item_number
从1开始,并递增1。
我想我应该在插入之前使用一些触发器来获取插入的user_item_number
的最大值username
并将其递增。但我不知道如何写这个触发器。
我也不知道如何考虑一个concurency访问(concurency插入多行具有相同的username
值)。当插入两个具有相同username
和user_item_number
的行时,我不希望出现约束违规错误,我希望触发捕获该错误,并再次增加user_item_number
值。< / p>
有什么想法吗?
答案 0 :(得分:2)
生成和维持这种无间隙序列真的很难。
获得相同结果的更好方法是使用窗口函数动态生成此类序列。类似的东西:
SELECT id, username, row_number() OVER (PARTITION BY username ORDER BY id) as user_item_number, item_value
from item_table;
它会给你想要的结果,并不会导致并发问题。它也将始终保持序列无间隙。
答案 1 :(得分:1)
Auto inc应该是唯一的,每张桌子只有一个。
所以基于你想要的东西
User(User_ID PK, ...)
UserItem(User_Item_ID PK, User_ID FK, ...)
UserItemValue(User_Item_Value_ID PK, User_Item_ID FK, ...)
是你应该从标准化的角度来看的地方
答案 2 :(得分:0)
我找到了解决方案。我写了触发器和程序:
create OR REPLACE function myinsert() RETURNS trigger as $$
BEGIN
if NEW.user_item_number is not null then return NEW;
end if;
loop
<<roolbac_to>>
declare
max INTEGER:=null;
begin
SELECT count(user_item_number) into max from item where username=NEW.username;
if max is null then
max:=1;
ELSE
max=max+1;
end if;
INSERT INTO item( username, user_item_number, item_value) VALUES (NEW.username,max, NEW.item_value);
exit;
exception WHEN unique_violation THEN
--do nothing
end;
end loop;
return null;
end;
$$ LANGUAGE 'plpgsql';
CREATE TRIGGER trig1
before insert
ON item
FOR EACH ROW
EXECUTE PROCEDURE myinsert();
这种酝酿可以创造出差距,但对我来说还是可以的。
我想触摸触发而不是插入,但这是不可能的。所以我在插入触发器之前做了并返回null。插入在程序内执行。 指令:
if NEW.user_item_number is not null then return NEW;
end if;
是不允许重新学习