使用触发器在PostgreSQL中重复自动增量生成的字段

时间:2016-06-10 07:53:23

标签: mysql postgresql

我在使用PostgreSQL中的触发器创建条形码时遇到问题。问题是,当客户端访问我的Web应用程序并同时插入数据时,我需要在我的目标项目中生成条形码。但问题是自动生成的条形码是重复的。任何解决方案,请帮助我。格式条形码为: 2016000000001 。 这是我的触发器:

DROP TABLE IF EXISTS "test"."barcode";
CREATE TABLE "test"."barcode" (
"id" int8 DEFAULT nextval('"test".t_id_seq'::regclass) NOT NULL,
"barcode" varchar(255) COLLATE "default"
)
WITH (OIDS=FALSE);

-----------------------------------------

CREATE OR REPLACE FUNCTION test.my_trigger_function()
  RETURNS trigger AS
$BODY$DECLARE new_barcode CHAR(50);

BEGIN
    SELECT
    (CASE 
        WHEN 
            CHAR_LENGTH (CAST(CAST(SUBSTRING(barcode, 5, 9) AS INTEGER) + 1 AS CHAR(20))) = 1 THEN 
                (SUBSTRING(barcode, 1, 4) || '00000000' || CAST((CAST(SUBSTRING(barcode, 5, 9) AS INTEGER) + 1)  AS CHAR(20)))
        WHEN 
            CHAR_LENGTH (CAST(CAST(SUBSTRING(barcode, 5, 9) AS INTEGER) + 1 AS CHAR(20))) = 2 THEN 
                (SUBSTRING(barcode, 1, 4) || '0000000' || CAST((CAST(SUBSTRING(barcode, 5, 9) AS INTEGER) + 1)  AS CHAR(20)))
        WHEN 
            CHAR_LENGTH (CAST(CAST(SUBSTRING(barcode, 5, 9) AS INTEGER) + 1 AS CHAR(20))) = 3 THEN 
                (SUBSTRING(barcode, 1, 4) || '000000' || CAST((CAST(SUBSTRING(barcode, 5, 9) AS INTEGER) + 1)  AS CHAR(20)))
        WHEN 
            CHAR_LENGTH (CAST(CAST(SUBSTRING(barcode, 5, 9) AS INTEGER) + 1 AS CHAR(20))) = 4 THEN 
                (SUBSTRING(barcode, 1, 4) || '00000' || CAST((CAST(SUBSTRING(barcode, 5, 9) AS INTEGER) + 1)  AS CHAR(20)))
        WHEN 
            CHAR_LENGTH (CAST(CAST(SUBSTRING(barcode, 5, 9) AS INTEGER) + 1 AS CHAR(20))) = 5 THEN 
                (SUBSTRING(barcode, 1, 4) || '0000' || CAST((CAST(SUBSTRING(barcode, 5, 9) AS INTEGER) + 1)  AS CHAR(20)))
        WHEN 
            CHAR_LENGTH (CAST(CAST(SUBSTRING(barcode, 5, 9) AS INTEGER) + 1 AS CHAR(20))) = 6 THEN 
                (SUBSTRING(barcode, 1, 4) || '000' || CAST((CAST(SUBSTRING(barcode, 5, 9) AS INTEGER) + 1)  AS CHAR(20)))
        WHEN 
            CHAR_LENGTH (CAST(CAST(SUBSTRING(barcode, 5, 9) AS INTEGER) + 1 AS CHAR(20))) = 7 THEN 
                (SUBSTRING(barcode, 1, 4) || '00' || CAST((CAST(SUBSTRING(barcode, 5, 9) AS INTEGER) + 1)  AS CHAR(20)))
        WHEN 
            CHAR_LENGTH (CAST(CAST(SUBSTRING(barcode, 5, 9) AS INTEGER) + 1 AS CHAR(20))) = 8 THEN 
                (SUBSTRING(barcode, 1, 4) || '0' || CAST((CAST(SUBSTRING(barcode, 5, 9) AS INTEGER) + 1)  AS CHAR(20)))
        WHEN 
            CHAR_LENGTH (CAST(CAST(SUBSTRING(barcode, 5, 9) AS INTEGER) + 1 AS CHAR(20))) = 9 THEN 
                (SUBSTRING(barcode, 1, 4) || CAST((CAST(SUBSTRING(barcode, 5, 9) AS INTEGER) + 1)  AS CHAR(20)))
        ELSE
            (CAST((CAST(TO_CHAR(NOW(),'yyyy') AS INTEGER)+1) AS CHAR(20)) || '000000001')
    END
    ) INTO new_barcode
FROM
    test. barcode
ORDER BY
    id DESC
LIMIT 1;

IF new_barcode IS NULL THEN 
    new_barcode = (CAST(TO_CHAR(NOW(),'yyyy') AS CHAR(20)) || '000000001'); 
END IF;
    NEW.barcode = new_barcode;
    RETURN NEW;
END;$BODY$
  LANGUAGE plpgsql VOLATILE
  COST 100;
ALTER FUNCTION test.my_trigger_function()
  OWNER TO postgres;
--------------------------------------------------

CREATE TRIGGER "my_trigger" BEFORE INSERT ON "test"."barcode"
FOR EACH ROW
EXECUTE PROCEDURE "test"."my_trigger_function"();

2 个答案:

答案 0 :(得分:1)

(我的眼睛流血......)这是你可以做的,只需使用SEQUENCE(保证不会产生任何重复):

CREATE SEQUENCE IF NOT EXISTS test.barcode_seq START 2016000000001;

CREATE OR REPLACE FUNCTION test.my_trigger_function() RETURNS trigger AS
$BODY$
DECLARE
  _barcode bigint;
BEGIN
  _barcode := nextval('test.barcode_seq');

  IF EXTRACT('year' FROM CURRENT_DATE) <> _barcode/1000000000 THEN
    _barcode := EXTRACT('year' FROM CURRENT_DATE) * 1000000000 + 1;
    PERFORM setval('test.barcode_seq', _barcode, true);
  END IF;

  NEW.barcode = _barcode::text;
  RETURN NEW;
END;
$BODY$ LANGUAGE plpgsql;

答案 1 :(得分:0)

试试这个:

创建一个序列:

create sequence test.barcode_sequence_byyear  start 1;

和您的触发器功能:

CREATE OR REPLACE FUNCTION test.my_trigger_function()
RETURNS trigger AS
$BODY$DECLARE new_barcode CHAR(50);
  declare count_barcode_of_year integer;

BEGIN
 --If it is the first barcode of year then init sequence to 1 
  select count(*) into count_barcode_of_year from test.barcode where  barcode like to_char(now(),'YYYY')||'%';
  if count_barcode_of_year=0 then 
      --set sequence to 1
       PERFORM setval('test.barcode_sequence_byyear'::regclass,1,false);
  end if;

  --Format your new barcode with year and sequence ( YEAR + Sequence with 9 significatives zeros : 
    NEW.barcode=to_char(now(),'YYYY')||to_char(nextval('test.barcode_sequence_byyear'::regclass),'FM'||repeat('0',9));
   RETURN NEW;
END;$BODY$
 LANGUAGE plpgsql VOLATILE
COST 100;
ALTER FUNCTION test.my_trigger_function()
OWNER TO postgres;