1.思路
先转换角分、再把整数部分转换成金额大写。金额大写需要注意中间有0,两个0其实拼接一个大写零即可。还有一个需要注意千到万、亿、万亿的转换,不仅仅是数字转换成金额大写,后面还需要拼接单位万、亿、万亿。
create or replace function number_to_chinese(num numeric)
RETURNS text AS $BODY$
declare
-- 人民币中文大写
chinese text := '';
-- 金额整数大写
chineseInteger text :='';
-- 金额小数大写
chineseDecimal text := '';
-- 人民币单位,注意pg数组下标从1开始
unit text[] := array['分', '角', '', '拾','佰','仟', '万', '亿', '万亿'];
-- 人民币大写
upperCase text[] := array['零','壹', '贰', '叁', '肆', '伍', '陆', '柒', '捌', '玖'];
-- 整数部分
integerPart bigint;
-- 角部分
jPart integer;
-- 分部分
fPart integer;
-- 小数部分
decimalPart integer;
-- 临时变量
tem1 integer;
tem2 integer;
temStr text := '';
-- 拾、佰、仟数组索引
i integer;
-- 万、亿、万亿数组索引
j integer;
-- 是否补零
addZero boolean := false;
-- 是否达到万、亿、万亿
isUpTo boolean := true;
-- 位数,用来判断0001这种情况
ws integer := 0;
begin
integerPart := floor(num); -- 整数
decimalPart := floor((num - integerPart) * 100); -- 小数部分
jPart := decimalPart / 10; -- 角
fPart := decimalPart % 10; -- 分
-- 判断数据有效性
if(num = 0 or num = 0.00) then
return '零元整';
elseif(num is null) then
return '';
end if;
-- 小数角分中文
if(jPart = 0 and fPart != 0) then
chineseDecimal := upperCase[fPart + 1] || unit[1];
elseif(jPart != 0 and fPart = 0) then
chineseDecimal := upperCase[jPart + 1] || unit[2];
else
chineseDecimal := upperCase[jPart + 1] || unit[2] || upperCase[fPart + 1] || unit[1];
end if;
-- 整数部分
j := 6;
while integerPart > 0 loop
-- 千、万、亿
tem1 := integerPart % 10000;
addZero := false;
i := 3;
ws := length(cast(tem1 as varchar));
while tem1 > 0 loop
tem2 := tem1 % 10;
-- 是否添加零
if(tem2 > 0 and addZero=false) then
addZero := true;
end if;
if(tem2 > 0 and ws > 1) then
temStr := upperCase[tem2 + 1] || unit[i];
elseif(tem2 = 0 and addZero=true and ws > 1) then
temStr := upperCase[tem2 + 1];
addZero := false;
elseif(tem2 > 0 and ws = 1 and integerPart / 10000 > 0) then
-- 区分10001中的两个1
temStr := upperCase[1] || upperCase[tem2 + 1] || unit[i];
elseif(tem2 > 0 and ws = 1 and integerPart / 10000 = 0) then
-- 区分10001中的两个1
temStr := upperCase[tem2 + 1] || unit[i];
end if;
-- 单位是否添加万、亿、万亿
if(j > 6 and isUpTo) then
chineseInteger := temStr || unit[j] || chineseInteger;
isUpTo := false;
else
chineseInteger := temStr || chineseInteger;
end if;
-- 单位递增
i := i +1;
tem1 := tem1 / 10;
-- 初始化临时变量
temStr := '';
end loop;
-- 初始化变量为下次循环做准备
integerPart := integerPart / 10000;
-- 0111处理这种情况
if(ws = 3 and integerPart > 0) then
chineseInteger := upperCase[1] || chineseInteger;
end if;
j := j + 1;
isUpTo := true;
end loop;
-- 判断是否是小数
if((jPart != 0 or fPart != 0) and num > 1) then
chineseInteger := chineseInteger || '元';
elseif(num > 1) then
chineseInteger := chineseInteger || '元整';
end if;
-- 金额大写
chinese := chineseInteger || chineseDecimal;
-- 截取掉100010
if(substring(chinese, 1, 2) = '壹拾') then
chinese = substring(chinese,2);
end if;
return chinese;
end;
$BODY$
language plpgsql;
2.测试
select number_to_chinese(521521521521.21)
伍仟贰佰壹拾伍亿贰仟壹佰伍拾贰万壹仟伍佰贰拾壹元贰角壹分
select number_to_chinese(520520520521.21)
伍仟贰佰零伍亿贰仟零伍拾贰万伍佰贰拾壹元贰角壹分