如何创建字母数字序列,例如 AAAA0000 等

jua*_*tto 5 postgresql perl postgresql-9.4

我想创建一个像这样的字母数字序列:

AAAA0000
AAAA0001
AAAA0002
AAAA0003
.
.
.
AAAA9999
AAAB0000
AAAB0001
.
.
.
ZZZZ9999
Run Code Online (Sandbox Code Playgroud)

我创建了这个存储过程来做到这一点,但它太慢了:

CREATE OR REPLACE FUNCTION public.fn_batch_seq()
  RETURNS text
  LANGUAGE plpgsql
AS
$body$
DECLARE
  v_sequence TEXT := '';
  v_next_sequence TEXT := '';
  v_existing_id BIGINT := 0;
BEGIN

  /*
  *  VARCHAR BATCH SEQUENCE FOR SIMCARDS
  */
  SELECT "sequence" FROM batch_sequence WHERE id = 1 INTO v_sequence;
  IF v_sequence = '' THEN
    RAISE NOTICE 'Error - No existe ningun registro en batch_sequence almacenado';
    RETURN -500;
  END IF;
  SELECT perl_increment(v_sequence) INTO v_next_sequence;

  IF v_next_sequence = '' THEN
    RAISE NOTICE 'Error - La siguiente secuencia generada devolvio null o vacio';
    RETURN -500;
  END IF;


  UPDATE batch_sequence SET "sequence" = v_next_sequence WHERE id = 1;
  RETURN v_next_sequence;

  EXCEPTION WHEN OTHERS THEN
  /*
  * Other errors
  */
  RAISE NOTICE 'Error General - Posibles causas: No existe la tabla batch_sequence o no existe ningun registro en la misma';
  RETURN -500;

END;
$body$
  VOLATILE
  COST 100;
Run Code Online (Sandbox Code Playgroud)

此过程使用表来存储序列:

CREATE TABLE batch_sequence
(
   id        serial   NOT NULL,
   sequence  text     DEFAULT 'AAAA0000'::text NOT NULL
);

-- Column id is associated with sequence public.batch_sequence_id_seq

ALTER TABLE batch_sequence
   ADD CONSTRAINT batch_sequence_pk
   PRIMARY KEY (id);
Run Code Online (Sandbox Code Playgroud)

为了增加序列,我使用 perl 过程:

CREATE OR REPLACE FUNCTION public.perl_increment(text)
  RETURNS text
  LANGUAGE plperl
AS
$body$
my ($x) = @_;
    if (not defined $x) {
        return undef;
    }
    ++$x;
$body$
  VOLATILE
  COST 100;
Run Code Online (Sandbox Code Playgroud)

对于大量数据,它的运行速度非常慢,因为它必须在插入每一行之前执行。有没有其他方法可以用或不用 Perl 来做到这一点?

mar*_*uso 2

我们可以使用几个生成一些简单序列的公共表表达式(CTE)来做到这一点......

with 

letters as
(select chr(i) as letter from generate_series(65,90) i),

digits as
(select lpad(i::text,4,'0') as digit from generate_series(0,9999) i)

select l1.letter || l2.letter || l3.letter || l4.letter || d.digit

from       letters l1
cross join letters l2
cross join letters l3
cross join letters l4
cross join digits d
Run Code Online (Sandbox Code Playgroud)
  • 我们的第一个 CTE 被命名为letters
  • letters生成一系列从 65 到 90 的数字,这恰好是字母“A”到“Z”的 ascii 代码,所以...
  • 我们可以通过chr(i)函数调用生成我们的角色
  • 此时letters表示字符集“A”到“Z”
  • 我们的下一个 CTE 是digits
  • digits生成一系列从 0 到 9999 的数字,因为我们要处理字符......
  • lpad(i::text,4,'0')允许我们将这一系列数字转换为左/零填充字符串
  • 此时digits代表一组字符 '0000', '0001', ... '9999'
  • 从这里我们只需要执行一系列操作cross joins并将字母/数字附加在一起

这是上述内容的dbfiddle 。

对于 dbfiddle,您可以删除该limit/offset子句以生成完整的集合,或者调整该limit/offset子句以查看一系列输出。

例如,limit 20 offset 59990我们得到:

?column?
--------
AAAF9990
AAAF9991
AAAF9992
AAAF9993
AAAF9994
AAAF9995
AAAF9996
AAAF9997
AAAF9998
AAAF9999
AAAG0000
AAAG0001
AAAG0002
AAAG0003
AAAG0004
AAAG0005
AAAG0006
AAAG0007
AAAG0008
AAAG0009
Run Code Online (Sandbox Code Playgroud)