【SQL】Oracle实现小写金额转换成大写的方法

今天看到论坛上有朋友询问,于是百度了一下,发现了曾有高人写过一个很牛的函数,崇拜一下,

这里我也记录一下。 论坛帖子 http://www.itpub.net/thread-1504656-1-1.html 当时的回帖:

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

http://www.itpub.net/thread-240281-1-1.html  有一个,高人写的,很不错。 
  
 
  
 
   
 
  
 
   实验效果如下: 
  
 
  

    SQL> create or replace function F_upper_money(p_num in number default null) 
  
 
  

      2  return nvarchar2 is 
  
 
  

      3  /*Ver:1.0 Created By xsb on 2003-8-18 For: 
  
 
  

      4          将金额数字(单位元)转换为大写(采用从低至高算法) 
  
 
  

      5          数字整数部分不得超过16位,可以是负数。 
  
 
  

      6  Ver:1.1 Modified By xsb on 2003-8-20 For:个位数处理也放在For循环中。 
  
 
  

      7  Ver:1.2 Modified By xsb on 2003-8-22 For:分后不带整字。 
  
 
  

      8  Ver:1.3 Modified By xsb on 2003-8-28 For:完善测试用例。 
  
 
  

      9  测试用例: 
  
 
  

    10  SET HEAD OFF 
  
 
  

    11  SET FEED OFF 
  
 
  

    12  select '无参数时='||f_upper_money() from dual; 
  
 
  

    13  select 'null='||f_upper_money(null) from dual; 
  
 
  

    14  select '0='||f_upper_money(0) from dual; 
  
 
  

    15  select '0.01='||f_upper_money(0.01) from dual; 
  
 
  

    16  select '0.126='||f_upper_money(0.126) from dual; 
  
 
  

    17  select '01.234='||f_upper_money(01.234) from dual; 
  
 
  

    18  select '10='||f_upper_money(10) from dual; 
  
 
  

    19  select '100.1='||f_upper_money(100.1) from dual; 
  
 
  

    20  select '100.01='||f_upper_money(100.01) from dual; 
  
 
  

    21  select '10000='||f_upper_money(10000) from dual; 
  
 
  

    22  select '10012.12='||f_upper_money(10012.12) from dual; 
  
 
  

    23  select '20000020.01='||f_upper_money(20000020.01) from dual; 
  
 
  

    24  select '3040506708.901='||f_upper_money(3040506708.901) from dual; 
  
 
  

    25  select '40005006078.001='||f_upper_money(40005006078.001) from dual; 
  
 
  

    26  select '-123456789.98='||f_upper_money(-123456789.98) from dual; 
  
 
  

    27  select '123456789123456789.89='||f_upper_money(123456789123456789.89) from dual; 
  
 
  

    28 
  
 
  

    29  */ 
  
 
  

    30  Result nvarchar2(100);--返回字符串 
  
 
  

    31  num_round nvarchar2(100) :=to_char(abs(round(p_num,2)));--转换数字为小数点后2位的字符(正数) 
  
 
  

    32  num_left nvarchar2(100);--小数点左边的数字 
  
 
  

    33  num_right nvarchar2(2);--小数点右边的数字 
  
 
  

    34  str1 nchar(10) :='零壹贰参肆伍陆柒捌玖';--数字大写 
  
 
  

    35  str2 nchar(16) :='元拾佰仟万拾佰仟亿拾佰仟万拾佰仟';--数字位数(从低至高) 
  
 
  

    36  num_pre number(1):=1;--前一位上的数字 
  
 
  

    37  num_current number(1);--当前位上的数字 
  
 
  

    38  num_count number:=0;--当前数字位数 
  
 
  

    39 
  
 
  

    40  begin 
  
 
  

    41  if p_num is null then return null;end if;--转换数字为null时返回null 
  
 
  

    42 
  
 
  

    43  select to_char( 
  
 
  

    44  nvl(substr(to_char(num_round),1, 
  
 
  

    45  decode(instr(to_char(num_round),'.'),0, 
  
 
  

    46  length(num_round),instr(to_char(num_round),'.')-1)), 
  
 
  

    47  0)) into num_left from dual;--取得小数点左边的数字 
  
 
  

    48  select substr(to_char(num_round), 
  
 
  

    49  decode(instr(to_char(num_round),'.'),0, 
  
 
  

    50  length(num_round)+1,instr(to_char(num_round),'.')+1),2) 
  
 
  

    51  into num_right from dual;--取得小数点右边的数字 
  
 
  

    52 
  
 
  

    53  if length(num_left)>16 then return '**********'; end if;--数字整数部分超过16位时 
  
 
  

    54 
  
 
  

    55    --采用从低至高的算法,先处理小数点右边的数字 
  
 
  

    56    if length(num_right)=2 then 
  
 
  

    57      if to_number(substr(num_right,1,1))=0 then 
  
 
  

    58       result:='零'||substr(str1,to_number(substr(num_right,2,1))+1,1)||'分'; 
  
 
  

    59      else 
  
 
  

    60       result:=substr(str1,to_number(substr(num_right,1,1))+1,1)||'角'|| 
  
 
  

    61               substr(str1,to_number(substr(num_right,2,1))+1,1)||'分'; 
  
 
  

    62      end if; 
  
 
  

    63    elsif length(num_right)=1 then 
  
 
  

    64      result:=substr(str1,to_number(substr(num_right,1,1))+1,1)||'角整'; 
  
 
  

    65    else 
  
 
  

    66      result :='整'; 
  
 
  

    67    end if; 
  
 
  

    68    --再处理小数点左边的数字 
  
 
  

    69    for i in reverse 1..length(num_left)  loop --(从低至高) 
  
 
  

    70        num_count:=num_count+1;--当前数字位数 
  
 
  

    71        num_current:=to_number(substr(num_left,i,1));--当前位上的数字 
  
 
  

    72        if num_current>0 then --当前位上数字不为0按正常处理 
  
 
  

    73           result:=substr(str1,num_current+1,1)||substr(str2,num_count,1)||result; 
  
 
  

    74        else --当前位上数字为0时 
  
 
  

    75            if mod(num_count-1,4)=0 then --当前位是元、万或亿时 
  
 
  

    76              result:=substr(str2,num_count,1)||result; 
  
 
  

    77              num_pre:=0;--元、万,亿前不准加零 
  
 
  

    78            end if; 
  
 
  

    79            if  num_pre>0 or length(num_left)=1 then  --上一位数字不为0或只有个位时 
  
 
  

    80                result:=substr(str1,num_current+1,1)||result; 
  
 
  

    81            end if; 
  
 
  

    82         end if; 
  
 
  

    83         num_pre:=num_current; 
  
 
  

    84    end loop; 
  
 
  

    85 
  
 
  

    86    if p_num<0 then --转换数字是负数时 
  
 
  

    87       result:='负'||result; 
  
 
  

    88    end if; 
  
 
  

    89 
  
 
  

    90    return Result; 
  
 
  

    91 
  
 
  

    92    exception 
  
 
  

    93    when others  then 
  
 
  

    94    raise_application_error(-20001,'数字转换大写出现错误!'||sqlerrm); 
  
 
  

    95  end ; 
  
 
  

    96  / 
  
 
  
 
   
 
  

    函数已创建。 
  
 
  
 
   
 
  

    SQL> SET HEAD OFF 
  
 
  

    SQL> SET FEED OFF 
  
 
  

    SQL> select '无参数时='||f_upper_money() from dual; 
  
 
  
 
   
 
  

    无参数时= 
  
 
  

    SQL> select 'null='||f_upper_money(null) from dual; 
  
 
  
 
   
 
  

    null= 
  
 
  

    SQL> select '0='||f_upper_money(0) from dual; 
  
 
  
 
   
 
  

    0=零元整 
  
 
  

    SQL> select '0.01='||f_upper_money(0.01) from dual; 
  
 
  
 
   
 
  

    0.01=零元零壹分 
  
 
  

    SQL> select '0.126='||f_upper_money(0.126) from dual; 
  
 
  
 
   
 
  

    0.126=零元壹角参分 
  
 
  

    SQL> select '01.234='||f_upper_money(01.234) from dual; 
  
 
  
 
   
 
  

    01.234=壹元贰角参分 
  
 
  

    SQL> select '10='||f_upper_money(10) from dual; 
  
 
  
 
   
 
  

    10=壹拾元整 
  
 
  

    SQL> select '100.1='||f_upper_money(100.1) from dual; 
  
 
  
 
   
 
  

    100.1=壹佰元壹角整 
  
 
  

    SQL> select '100.01='||f_upper_money(100.01) from dual; 
  
 
  
 
   
 
  

    100.01=壹佰元零壹分 
  
 
  

    SQL> select '10000='||f_upper_money(10000) from dual; 
  
 
  
 
   
 
  

    10000=壹万元整 
  
 
  

    SQL> select '10012.12='||f_upper_money(10012.12) from dual; 
  
 
  
 
   
 
  

    10012.12=壹万零壹拾贰元壹角贰分 
  
 
  

    SQL> select '20000020.01='||f_upper_money(20000020.01) from dual; 
  
 
  
 
   
 
  

    20000020.01=贰仟万零贰拾元零壹分 
  
 
  

    SQL> select '3040506708.901='||f_upper_money(3040506708.901) from dual; 
  
 
  
 
   
 
  

    3040506708.901=参拾亿肆仟零伍拾万陆仟柒佰零捌元玖角整 
  
 
  

    SQL> select '40005006078.001='||f_upper_money(40005006078.001) from dual; 
  
 
  
 
   
 
  

    40005006078.001=肆佰亿零伍佰万陆仟零柒拾捌元整 
  
 
  

    SQL> select '-123456789.98='||f_upper_money(-123456789.98) from dual; 
  
 
  
 
   
 
  

    -123456789.98=负壹亿贰仟参佰肆拾伍万陆仟柒佰捌拾玖元玖角捌分 
  
 
  

    SQL> select '123456789123456789.89='||f_upper_money(123456789123456789.89) from dual; 
  
 
  
 
   
 
  

    123456789123456789.89=********** 
  
 
  

    SQL> 
    以上。