Oracle中金额数字转换为大写汉字

这个版本的函数,解决的问题

  1. 零出现重复或不出现的问题
  2. 当金额只有角或分的显示问题
  3. 金额为整数时,是否想要带 整 字
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;
相关推荐
有味道的男人2 小时前
抖音关键词搜索,视频详情api
linux·数据库·音视频
fly spider2 小时前
MySQL之Buffer Pool
数据库·mysql
程序员老邢2 小时前
【技术底稿 13】内网 Milvus 2.3.0 向量数据库全流程部署(商助慧 AI 底座,Attu 可视化)
java·数据库·人工智能·ai·语言模型·milvus
XDHCOM2 小时前
ORA-38456: 属性集状态不一致,Oracle报错修复对比,远程处理方案选择
数据库·oracle
羊小蜜.2 小时前
Mysql 14: 存储引擎——架构、引擎对比与锁机制
数据库·mysql·架构
爱学习的小囧2 小时前
VM硬件版本20与17核心区别(ESXi 8.0适配+实操指南)
运维·服务器·网络·数据库·esxi·vmware·虚拟化
heimeiyingwang2 小时前
【架构实战】Redis性能调优与内存优化策略
数据库·redis·架构
Flying pigs~~3 小时前
检索增强生成RAG项目tools_04:flask➕fastapi➕高并发
数据库·python·flask·大模型·fastapi·异步
minebmw73 小时前
Oracle 19.29 中 ORA-12751 错误完全解析:从通用问题到 minact-scn 场景
数据库·oracle