每个外键分别自动递增

Mar*_*usz 6 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)
    )
Run Code Online (Sandbox Code Playgroud)

在此处输入图片说明

我想user_item_number分别为每个自动增加username。下图显示了示例。对于每个username:(user1user2user_item_number从1开始并递增1。 在此处输入图片说明

我想,我应该插入其中得到的最大值之前使用一些触发user_item_numberusername,其插入并加一。但是我不知道如何编写触发器。

我也不知道如何考虑并发访问(并发插入多个具有相同值的行username)。当插入两行相同的行usernameuser_item_number插入时,我不想收到约束违反错误,我希望该触发器捕获该错误并再次增加 user_item_number值。

任何的想法?

Mar*_*usz 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();
Run Code Online (Sandbox Code Playgroud)

这个解决方案允许创建间隙,但对我来说没问题。

我想使用触发器而不是插入,但这是不可能的。所以我在插入触发器之前做了并返回null。插入是在过程内部执行的。操作说明:

if NEW.user_item_number is not null then return NEW;
    end if;
Run Code Online (Sandbox Code Playgroud)

就是不允许再次发生