这个版本的函数,解决的问题
- 零出现重复或不出现的问题
- 当金额只有角或分的显示问题
- 金额为整数时,是否想要带 整 字
sql
CREATE OR REPLACE FUNCTION NUM_TO_CAPITAL(MONEY IN NUMBER)
RETURN VARCHAR2
IS
TYPE STRING_ARRAY IS TABLE OF VARCHAR2(10);
DIGIT_STR STRING_ARRAY := STRING_ARRAY('零','壹','贰','叁','肆','伍','陆','柒','捌','玖');
V_NUM VARCHAR2(100);
V_INT VARCHAR2(100);
V_DEC VARCHAR2(10);
V_RESULT VARCHAR2(300) := '';
V_SECTION VARCHAR2(4);
V_SEC_RES VARCHAR2(50) := '';
V_I NUMBER := 0;
V_HAS_NUM BOOLEAN;
V_IS_OVER_WAN BOOLEAN := FALSE; -- 是否 >= 万元
BEGIN
-- 1. 空值处理
IF MONEY IS NULL THEN
RETURN '';
END IF;
-- 2. 负数处理
IF MONEY < 0 THEN
RETURN '负' || NUM_TO_CAPITAL(ABS(MONEY));
END IF;
-- 3. 金额上限校验
IF MONEY >= POWER(10,16) THEN
RAISE_APPLICATION_ERROR(-20001, '金额超出转换范围(最大支持9999999999999999.99)');
END IF;
-- 4. 格式化拆分整数、小数
V_NUM := TO_CHAR(ROUND(MONEY, 2), 'FM9999999999999990.00');
V_INT := SUBSTR(V_NUM, 1, INSTR(V_NUM, '.') - 1);
V_DEC := SUBSTR(V_NUM, INSTR(V_NUM, '.') + 1);
-- 5. 整数部分为0时,不拼接"零元",直接处理小数
IF V_INT != '0' THEN
WHILE LENGTH(V_INT) > 0 LOOP
IF LENGTH(V_INT) > 4 THEN
V_SECTION := SUBSTR(V_INT, LENGTH(V_INT)-3, 4);
V_INT := SUBSTR(V_INT, 1, LENGTH(V_INT)-4);
ELSE
V_SECTION := LPAD(V_INT, 4, '0');
V_INT := '';
END IF;
V_SEC_RES := '';
V_HAS_NUM := FALSE;
-- 逐位转换:仟、佰、拾、个
FOR J IN 1..4 LOOP
DECLARE
D CHAR(1) := SUBSTR(V_SECTION, J, 1);
U VARCHAR2(2) := CASE J WHEN 1 THEN '仟' WHEN 2 THEN '佰' WHEN 3 THEN '拾' ELSE '' END;
BEGIN
IF D != '0' THEN
IF V_SEC_RES IS NOT NULL AND SUBSTR(V_SECTION, J-1, 1) = '0' THEN
V_SEC_RES := V_SEC_RES || '零';
END IF;
V_SEC_RES := V_SEC_RES || DIGIT_STR(TO_NUMBER(D)+1) || U;
V_HAS_NUM := TRUE;
END IF;
END;
END LOOP;
-- 追加单位:万、亿、万亿
IF V_HAS_NUM THEN
CASE V_I
WHEN 1 THEN
V_SEC_RES := V_SEC_RES || '万';
V_IS_OVER_WAN := TRUE;
WHEN 2 THEN
V_SEC_RES := V_SEC_RES || '亿';
V_IS_OVER_WAN := TRUE;
WHEN 3 THEN
V_SEC_RES := V_SEC_RES || '万亿';
V_IS_OVER_WAN := TRUE;
ELSE NULL;
END CASE;
V_RESULT := V_SEC_RES || V_RESULT;
ELSIF V_I = 1 AND V_RESULT IS NOT NULL THEN
IF SUBSTR(V_RESULT, 1, 1) != '零' THEN
V_RESULT := '零' || V_RESULT;
END IF;
END IF;
V_I := V_I + 1;
END LOOP;
-- 整数部分收尾
IF V_RESULT IS NOT NULL THEN
V_RESULT := V_RESULT || '元';
END IF;
END IF;
-- 6. 小数部分处理
IF V_DEC != '00' THEN
-- 角
IF SUBSTR(V_DEC,1,1) != '0' THEN
V_RESULT := V_RESULT || DIGIT_STR(TO_NUMBER(SUBSTR(V_DEC,1,1))+1) || '角';
ELSIF SUBSTR(V_DEC,2,1) != '0' AND V_RESULT IS NOT NULL THEN
V_RESULT := V_RESULT || '零';
END IF;
-- 分
IF SUBSTR(V_DEC,2,1) != '0' THEN
V_RESULT := V_RESULT || DIGIT_STR(TO_NUMBER(SUBSTR(V_DEC,2,1))+1) || '分';
END IF;
ELSE
-- 核心规则:只有 ≥ 万元 且无小数时才加"整"
IF V_RESULT IS NOT NULL AND V_IS_OVER_WAN THEN
V_RESULT := V_RESULT || '整';
END IF;
END IF;
-- 7. 处理全零金额
IF V_RESULT IS NULL OR V_RESULT = '' THEN
RETURN '零元';
END IF;
RETURN V_RESULT;
END NUM_TO_CAPITAL;