获取PL / SQL中String的最后一个数字部分

时间:2012-12-03 07:40:37

标签: regex oracle plsql

在PL / SQL中,有没有办法计算下一个序列号,如'A1B0010C'。下一个序列号为A1B0011C(+1)。我的想法是检索数字部分,增加它返回返回字符串。 我可以在java中执行此操作,但将超过1000个元素传递给Oracle将导致IN子句出现问题。 所以请帮忙,任何建议都表示赞赏。

3 个答案:

答案 0 :(得分:2)

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

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

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

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

答案 1 :(得分: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

答案 2 :(得分: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;