每个外键单独自动增量

时间:2013-08-06 12:17:41

标签: database postgresql

我有两张桌子:

 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)
    )

enter image description here

我想为每个user_item_number分别自动增加username。下图显示了示例。对于每个username :( user1user2user_item_number从1开始,并递增1。 enter image description here

我想我应该在插入之前使用一些触发器来获取插入的user_item_number的最大值username并将其递增。但我不知道如何写这个触发器。

我也不知道如何考虑一个concurency访问(concurency插入多行具有相同的username值)。当插入两个具有相同usernameuser_item_number的行时,我不希望出现约束违规错误,我希望触发捕获该错误,并再次增加user_item_number值。< / p>

有什么想法吗?

3 个答案:

答案 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;

是不允许重新学习