首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 數據庫知識 >  >> Oracle 資料庫 >> Oracle 資料庫基礎

Oracle PL/SQL 實戰:數字金額自動轉中文大寫函數完整實現

     編輯:Oracle 資料庫基礎

業務場景

財務報表、支票打印、合同生成中,金額必須以中文大寫(壹貳叁...)顯示,且遵循「圓/角/分/整」規範。Oracle 無內建函數,需自行實現。

函數規格

  • 輸入:NUMBER 類型金額,任意長度。
  • 處理:小數點後保留兩位(四捨五入或截斷,代碼採用截斷 FLOOR(MONEY*100))。
  • 輸出:VARCHAR2 中文大寫字符串。
    • 最低位為「圓」或「角」 → 尾部加「整」。
    • 最低位為「分」 → 不加「整」。
    • 零值返回「零圓整」。

核心演算法邏輯

  1. 拆分整數/小數部: STR_YUAN = TO_CHAR(FLOOR(MONEY)),STR_YUAN_FEN = TO_CHAR(FLOOR(MONEY*100))。
  2. 映射表:數字 0-9 → 「零」到「玖」;位權 -2(分)、-1(角)、1(個)、2(十)、3(百)、4(千)、5(萬)、9(億) → 單位字符。
  3. 整數部遍歷:從低位向高位循環,每 4 位一個萬/億單位,遇非零寫數字+單位,遇零按「四位一判斷」決定是否寫單位(避免連續零冗餘)。
  4. 小數部處理:直接映射角、分位,非零才輸出。
  5. 尾部修飾:有整數部加「圓」,無小數部或小數部僅有角則加「整」。

完整代碼(可直接部署)

CREATE OR REPLACE FUNCTION MONEY2CHINESE (MONEY IN NUMBER) RETURN VARCHAR2 IS
  STR_YUAN       VARCHAR2(150);
  STR_YUAN_FEN   VARCHAR2(152);
  N_U_M_LEN_YUAN NUMBER;
  N_U_M_LEN_YF   NUMBER;
  STR_RST_YUAN   VARCHAR2(600);
  STR_RST_FEN    VARCHAR2(200);
  STR_RST        VARCHAR2(800);
  TYPE TYP_TAB_MAPPING IS TABLE OF VARCHAR2(2) INDEX BY BINARY_INTEGER;
  TAB_NUM_MAP    TYP_TAB_MAPPING;
  TAB_UNIT_MAP   TYP_TAB_MAPPING;
  NUM_UNIT_IDX   NUMBER;
  I              NUMBER;
  J              NUMBER;
  CHAR_CUR_NUM   CHAR(1);
BEGIN
  IF MONEY IS NULL THEN RETURN NULL; END IF;

  STR_YUAN := TO_CHAR(FLOOR(MONEY));
  IF STR_YUAN = '0' THEN
    N_U_M_LEN_YUAN := 0;
    STR_YUAN_FEN := LPAD(TO_CHAR(FLOOR(MONEY*100)),2,'0');
  ELSE
    N_U_M_LEN_YUAN := LENGTH(STR_YUAN);
    STR_YUAN_FEN := TO_CHAR(FLOOR(MONEY*100));
  END IF;

  IF STR_YUAN_FEN = '0' THEN
    N_U_M_LEN_YF := 0;
  ELSE
    N_U_M_LEN_YF := LENGTH(STR_YUAN_FEN);
  END IF;

  IF N_U_M_LEN_YUAN = 0 OR N_U_M_LEN_YF = 0 THEN
    RETURN '零圓整';
  END IF;

  -- 數字映射
  TAB_NUM_MAP(0):='零'; TAB_NUM_MAP(1):='壹'; TAB_NUM_MAP(2):='貳';
  TAB_NUM_MAP(3):='叁'; TAB_NUM_MAP(4):='肆'; TAB_NUM_MAP(5):='伍';
  TAB_NUM_MAP(6):='陸'; TAB_NUM_MAP(7):='柒'; TAB_NUM_MAP(8):='捌';
  TAB_NUM_MAP(9):='玖';

  -- 單位映射(負索引為小數位)
  TAB_UNIT_MAP(-2):='分'; TAB_UNIT_MAP(-1):='角';
  TAB_UNIT_MAP(1):='';  TAB_UNIT_MAP(2):='拾'; TAB_UNIT_MAP(3):='佰';
  TAB_UNIT_MAP(4):='仟'; TAB_UNIT_MAP(5):='萬';
  TAB_UNIT_MAP(6):='拾'; TAB_UNIT_MAP(7):='佰'; TAB_UNIT_MAP(8):='仟';
  TAB_UNIT_MAP(9):='億';

  -- 整數部主循環
  FOR I IN 1..N_U_M_LEN_YUAN LOOP
    J := N_U_M_LEN_YUAN - I + 1;
    NUM_UNIT_IDX := MOD(I,8);
    IF NUM_UNIT_IDX = 0 THEN NUM_UNIT_IDX := 8; END IF;

    IF NUM_UNIT_IDX = 1 AND I > 1 THEN
      STR_RST_YUAN := TAB_UNIT_MAP(9) || STR_RST_YUAN; -- 億單位
    END IF;

    CHAR_CUR_NUM := SUBSTR(STR_YUAN,J,1);
    IF CHAR_CUR_NUM <> '0' THEN
      STR_RST_YUAN := TAB_NUM_MAP(CHAR_CUR_NUM) || TAB_UNIT_MAP(NUM_UNIT_IDX) || STR_RST_YUAN;
    ELSE
      IF (I = 1 OR I = 5) AND SUBSTR(STR_YUAN,J-3,4) <> '0000' THEN
        STR_RST_YUAN := TAB_UNIT_MAP(NUM_UNIT_IDX) || STR_RST_YUAN; -- 萬/億位保留單位
      ELSIF SUBSTR(STR_YUAN,J+1,1) <> '0' THEN
        STR_RST_YUAN := TAB_NUM_MAP(CHAR_CUR_NUM) || STR_RST_YUAN; -- 中間零保留一個「零」
      END IF;
    END IF;
  END LOOP;

  -- 小數部
  FOR I IN -2..-1 LOOP
    J := N_U_M_LEN_YUAN - I;
    CHAR_CUR_NUM := SUBSTR(STR_YUAN_FEN,J,1);
    IF CHAR_CUR_NUM <> '0' THEN
      STR_RST_FEN := TAB_NUM_MAP(CHAR_CUR_NUM) || TAB_UNIT_MAP(I) || STR_RST_FEN;
    END IF;
  END LOOP;

  -- 尾部修飾
  IF STR_RST_YUAN IS NOT NULL THEN STR_RST_YUAN := STR_RST_YUAN || '圓'; END IF;
  IF STR_RST_FEN IS NULL THEN
    STR_RST_YUAN := STR_RST_YUAN || '整';
  ELSIF LENGTH(STR_RST_FEN)=2 AND SUBSTR(STR_RST_FEN,2)='角' THEN
    STR_RST_FEN := STR_RST_FEN || '整';
  END IF;

  STR_RST := STR_RST_YUAN || STR_RST_FEN;
  -- 可選:替換「億零」「萬零」為「億」「萬」
  RETURN STR_RST;
END MONEY2CHINESE;
/

測試驗證

SELECT MONEY2CHINESE(932402934024.213) FROM DUAL;
-- 結果:玖仟叁佰貳拾肆億零貳佰玖拾叁萬肆仟零貳拾肆圓貳角整

擴展建議

  • 若需四捨五入分位,將 FLOOR 改為 ROUND(MONEY,2)。
  • 超大金額(超過 VARCHAR2 4000)可改用 CLOB 返回。
  • 集成至報表工具(BI Publisher、APEX)或觸發器自動填充大寫字段。
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved