0

在 PL/SQL 中,有没有办法从另一个序列号(如“A1B0010C”)计算下一个序列号。下一个序列号将是 A1B0011C (+1)。我的想法是检索数字部分,增加它得到返回字符串。我可以在 java 中做到这一点,但是将超过 1000 个元素传递给 Oracle 会导致 IN 子句出现问题。所以请帮助,任何建议表示赞赏。

4

3 回答 3

2

尝试编写一些这样的递归函数

此函数返回下一个字符。例如:C 之后的 D。Z 之后的 0。

create or replace function get_next_character(ch char)
return char
is
result_ch char(1) := ch;
begin

IF UPPER(ch) = 'Z' or ch = '9' THEN
  result_ch := 'A';
ELSE
  result_ch := chr(ascii(ch) + 1);
END IF;

return upper(result_ch);
end get_next_character;

这是您返回下一个序列号的实际函数因此,如果您的输入是“ A1B0010C ”,它会生成“ A1B0010D

create or replace function get_next_serial(p_serial IN varchar2)  -- PASS THE REQUIRED ARGUMENTS
    return varchar2
    IS
    v_ret_serial varchar2(100);
    v_in_serial varchar2(100) := p_serial;
    tmp varchar2(100);
    last_char char(1);
    begin

    tmp := v_in_serial;

    for i in reverse 1..length(v_in_serial) loop

      last_char := substr(tmp, length(tmp));
      last_char := get_next_character(last_char);

      tmp := substr(v_in_serial, 1, length(tmp)-1);
      v_in_serial := substr(v_in_serial, 1, i-1) || last_char || substr(v_in_serial, i+1);

      IF last_char <> 'A' then
        exit;
      END IF;
    end loop;

    IF last_char = 'A' THEN
      v_in_serial:= 'A'||v_in_serial;
    END IF;
    return UPPER(v_in_serial);

    exception
    when NO_DATA_FOUND then
      return 'AA';
    when others then
      return null;
    end get_next_serial;

你可以在任何你想要的地方调用这个函数 (get_next_serial('abc'));

select get_next_serial('ALK0989KJ') from dual

您可以将这两个功能放在一个包中,并在您方便的时候使用。

于 2012-12-03T08:20:47.997 回答
1

您可以通过使用以下Regexp_*功能组合来实现它:

SQL> with t1 as(
  2    select 'A1B0010C' col from dual
  3  )
  4  select regexp_replace(col, '[[:digit:]]+'
  5                       , to_char(to_number(regexp_substr(col, '[[:digit:]]+',1,2) + 1), 'fm0000')
  6                       , 1
  7                       , 2
  8                       ) as Res
  9    from t1
 10  ;

RES
------------
A1B0011C

更新回应评论。

SQL> with t1 as(
  2        select 'A1B0010C'     col from dual union all
  3        select 'A1B0010C2'    col from dual union all
  4        select 'A1B0012C001'  col from dual union all
  5        select 'S000001'      col from dual
  6      )
  7  select col
  8       , regexp_replace(col
  9                       , '([[:digit:]]+)([[:alpha:]]+$|$)'
 10                       ,  LPad(to_char(to_number(num) + 1), length(num), '0') || '\2'
 11                       ) as Res
 12    from (select col
 13               , regexp_substr(col, '([[:digit:]]+)([[:alpha:]]+$|$)', 1, 1, 'i', 1) as num
 14             from t1
 15            )
 16  ;

COL            RES
-----------    -----------------
A1B0010C       A1B0011C
A1B0010C2      A1B0010C3
A1B0012C001    A1B0012C002
S000001        S000002
于 2012-12-03T08:19:59.377 回答
0
create or replace function nextSerial(s in varchar2) return varchar2 as
  i integer;
  done boolean := false;
  c char;
  newserial varchar2(4000);
begin
  newserial := s;

  i := length(newserial);
  while i>0 and not done loop
    c := substr(newserial, i, 1);
    if c='9' then
      newserial := substr(newserial, 1, i-1) || '0' || substr(newserial, i+1);
    elsif c>='0' and c<='8' then
      c := chr(ascii(c)+1);
      newserial := substr(newserial, 1, i-1) || c || substr(newserial, i+1);
      done := true;
    end if;
    i := i-1;
  end loop;

  if not done then
    newserial := '1' || newserial;
  end if;

  return newserial;
end;
于 2012-12-03T08:33:59.033 回答