【问题标题】:Auto increment depending on value of column in PostgreSQL根据 PostgreSQL 中列的值自动递增
【发布时间】:2017-03-22 00:02:02
【问题描述】:

接下来的问题是,我是否可以根据特定列(此处为 business_uuid)的值自动递增(verification_number),以便根据 business_uuid 自己的最高验证号数,verification_number 递增一 (1)?

数据库如下所示: 表:验证

verification_id = integer, sequence (Primary Key)
business_uuid = text
verification_number = integer

verification_id 是此表中的主键,我希望 verify_number 遵循它自己的自动增量,具体取决于仅针对 business_uuid 过滤的最大值。

business_uuid 是每个企业的唯一标识符。

有可能吗?

【问题讨论】:

  • 你能给出样本输入和它的输出吗?
  • 可以通过触发功能自动填充数值。

标签: postgresql primary-key auto-increment


【解决方案1】:

我认为这是一个糟糕的设计,但如果你真的想要这样,你可以通过以下方式实现它:

  1. 创建唯一约束:

    ALTER TABLE verification
       ADD CONSTRAINT verification_uuid_nr_unique
          UNIQUE (business_uuid, verification_number);
    

    由此创建的索引也会使后面的触发函数更快。

  2. 创建BEFORE触发器修改verification_number

    CREATE OR REPLACE FUNCTION veritrig() RETURNS trigger
       LANGUAGE plpgsql AS
    $$BEGIN
       SELECT COALESCE(max(verification_number)+1, 1) INTO NEW.verification_number
          FROM verification
          WHERE business_uuid = NEW.business_uuid;
       RETURN NEW;
    END;$$;
    
    CREATE TRIGGER veritrig
       BEFORE INSERT OR UPDATE ON verification FOR EACH ROW
       EXECUTE PROCEDURE veritrig();
    
  3. 像这样插入新值:

    INSERT INTO verification (business_uuid) VALUES ('42');
    

    然后verification_number 将根据您的需要设置。

但是,并发存在问题。

如果多个会话同时尝试插入或更新表,您将收到如下错误:

ERROR:  duplicate key value violates unique constraint "verification_uuid_nr_unique"
DETAIL:  Key (business_uuid, verification_number)=(43, 1) already exists.

这是因为并发修改中的SELECT 语句只会看到当前(提交的)表内容,并且可能错误地尝试为business_uuid 插入相同的verification_number

没有办法避免锁定表的不足。但是,如果您收到这样的错误,您可以简单地重试该事务,并且很有可能下次它会起作用。

【讨论】:

    【解决方案2】:

    不清楚是否要将verification_number 保存到表中,但可以在查询时创建:

    select verification_id, business_uuid, 
        row_number() over(
            partition by business_uuid
            order by verification_id
        ) as verification_number
    from verification
    

    上述方法的问题是,如果行被删除,verification_number 会改变

    Window functions

    【讨论】:

      【解决方案3】:
      CREATE OR REPLACE FUNCTION public.creaid(
          IN key_field text,
          IN table_mane text,
          OUT id integer)
          RETURNS integer AS
      $BODY$
          DECLARE  maxid INT;
          BEGIN
              EXECUTE 'SELECT max('||key_field||') FROM '||table_name INTO maxid;
              IF maxid IS NULL THEN
                  id = 1;
              ELSE
                  id = maxid + 1;
              END IF;
          END;
      $BODY$
      LANGUAGE plpgsql VOLATILE
      COST 100;
      

      然后,您可以将该函数调用为数据库中每个表的每个键值的默认值,如下所示:

      DEFAULT creaid('key_field'::text, 'table_name'::text)
      

      【讨论】:

        猜你喜欢
        • 2021-10-31
        • 2018-08-06
        • 2018-10-14
        • 1970-01-01
        • 2016-08-19
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多