| @OutputMode | 名稱 | 輸入 101.00 | 輸出範例 |
| 1 | 直接翻譯 | 逐位轉換 | 壹零壹元零分 |
| 0 | 讀法模式 | 按中文數位單位 | 壹佰零壹元整 |
核心演算法:逆序掃描 + 單位映射表
完整修正版程式碼 (SQL Server 2000 相容)
CREATE PROCEDURE dbo.usp_NumberToChineseCurrency
@Amount NUMERIC(15,2),
@OutputMode TINYINT,
@ChineseText VARCHAR(200) OUTPUT
AS
BEGIN
SET NOCOUNT ON;
-- 數字到漢字映射
DECLARE @Digits TABLE (Num CHAR(1), Chi CHAR(1));
INSERT @Digits VALUES ('0','零'),('1','壹'),('2','貳'),('3','叁'),('4','肆'),
('5','伍'),('6','陸'),('7','柒'),('8','捌'),('9','玖');
-- 整數部分單位 (個、十、百、千、萬、十萬、百萬、千萬、億...)
DECLARE @IntUnits TABLE (Pos INT, Unit VARCHAR(2));
INSERT @IntUnits VALUES
(1,''),(2,'拾'),(3,'佰'),(4,'仟'),
(5,'萬'),(6,'拾'),(7,'佰'),(8,'仟'),
(9,'億'),(10,'拾'),(11,'佰'),(12,'仟'),
(13,'兆'),(14,'拾'),(15,'佰'),(15,'仟');
-- 小數部分單位 (分、角)
DECLARE @DecUnits TABLE (Pos INT, Unit VARCHAR(2));
INSERT @DecUnits VALUES (1,'分'),(2,'角');
-- 格式化為固定 15 整數位 + 2 小數位,去除空格
DECLARE @NumStr VARCHAR(20);
SET @NumStr = REPLACE(STR(@Amount, 18, 2), ' ', ''); -- 如 "000000000012345.67"
DECLARE @IntPart VARCHAR(15) = LEFT(@NumStr, 15);
DECLARE @DecPart VARCHAR(2) = RIGHT(@NumStr, 2);
DECLARE @Result VARCHAR(200) = '';
DECLARE @Pos INT, @Digit CHAR(1), @Unit VARCHAR(2), @ChiDigit CHAR(1);
DECLARE @LastNonZero BIT = 0; -- 追蹤前一位是否非零,控制「零」輸出
-- ===== 整數部分:從個位(右)向左掃描 =====
SET @Pos = 15;
WHILE @Pos >= 1
BEGIN
SET @Digit = SUBSTRING(@IntPart, @Pos, 1);
IF @Digit <> '0'
BEGIN
SELECT @ChiDigit = Chi FROM @Digits WHERE Num = @Digit;
SELECT @Unit = Unit FROM @IntUnits WHERE Pos = (16 - @Pos); -- 位置對應
-- 處理連續零:若前一位是零且當前非零,補一個「零」
IF @LastNonZero = 0 AND @Result <> ''
SET @Result = '零' + @Result;
SET @Result = @ChiDigit + @Unit + @Result;
SET @LastNonZero = 1;
END
ELSE
BEGIN
-- 當前位是零
-- 萬/億/兆 位必須顯示單位(即使前面有零)
IF (16 - @Pos) IN (5, 9, 13) -- 萬、億、兆位
BEGIN
SELECT @Unit = Unit FROM @IntUnits WHERE Pos = (16 - @Pos);
IF @LastNonZero = 1 -- 前一位非零,才加單位
SET @Result = @Unit + @Result;
SET @LastNonZero = 0;
END
ELSE
SET @LastNonZero = 0; -- 普通位零不輸出,只標記
END
SET @Pos = @Pos - 1;
END
-- 處理純零整數部分
IF @Result = '' SET @Result = '零';
-- 加上「元」
SET @Result = @Result + '元';
-- ===== 小數部分 =====
IF @DecPart = '00'
BEGIN
IF @OutputMode = 0 SET @Result = @Result + '整'; -- 讀法模式加「整」
END
ELSE
BEGIN
-- 角
SET @Digit = SUBSTRING(@DecPart, 1, 1);
IF @Digit <> '0'
BEGIN
SELECT @ChiDigit = Chi FROM @Digits WHERE Num = @Digit;
SET @Result = @Result + @ChiDigit + '角';
SET @LastNonZero = 1;
END
ELSE
SET @LastNonZero = 0;
-- 分
SET @Digit = SUBSTRING(@DecPart, 2, 1);
IF @Digit <> '0'
BEGIN
SELECT @ChiDigit = Chi FROM @Digits WHERE Num = @Digit;
-- 若角為零且分非零,需補「零」
IF @LastNonZero = 0 AND @Result NOT LIKE '%整'
SET @Result = @Result + '零';
SET @Result = @Result + @ChiDigit + '分';
END
ELSE IF @LastNonZero = 1 AND @OutputMode = 0
SET @Result = @Result + '整'; -- 有角無分,讀法模式加「整」
END
-- 直接翻譯模式:移除單位「拾佰仟萬億兆」,僅保留數字與「元角分」
IF @OutputMode = 1
BEGIN
SET @Result = REPLACE(@Result, '拾', '');
SET @Result = REPLACE(@Result, '佰', '');
SET @Result = REPLACE(@Result, '仟', '');
SET @Result = REPLACE(@Result, '萬', '');
SET @Result = REPLACE(@Result, '億', '');
SET @Result = REPLACE(@Result, '兆', '');
SET @Result = REPLACE(@Result, '整', '');
END
SET @ChineseText = @Result;
END;
測試驗證矩陣
| 輸入金額 | 模式 0 (讀法) | 模式 1 (直譯) | 關鍵驗證點 |
| 0.00 | 零元整 | 零元 | 零值處理 |
| 0.01 | 零元零壹分 | 零元零壹分 | 純分 |
| 0.10 | 零元壹角整 | 零元壹角 | 純角 |
| 100.00 | 壹佰元整 | 壹零零元 | 整百 |
| 101.00 | 壹佰零壹元整 | 壹零壹元 | 中間零 |
| 1001.00 | 壹仟零壹元整 | 壹零零壹元 | 千位零 |
| 10001.00 | 壹萬零壹元整 | 壹零零零壹元 | 萬位零 |
| 123456789.45 | 壹億貳仟叁佰肆拾伍萬陸仟柒佰捌拾玖元肆角伍分 | 壹貳叁肆伍陸柒捌玖元肆伍分 | 完整長數字 |
| 100000000.00 | 壹億元整 | 壹零零零零零零零零元 | 億位邊界 |
| 999999999999999.99 | 玖仟玖佰玖拾玖兆玖仟玖佰玖拾玖億玖仟玖佰玖拾玖萬玖仟玖佰玖拾玖元玖角玖分 | ...(超長) | 最大值 999 兆 |
關鍵修正點對比 (vs 舊版本)
| 問題 | 舊版本行為 | 本版本修正 |
| 中間零重複/遺漏 | 「壹佰零零壹」或「壹佰壹」 | 單一「零」標記邏輯,配合 @LastNonZero 狀態機 |
| 萬/億/兆位零不顯示單位 | 「壹億零壹」→ 少「萬」字 | 大位零強制輸出單位,如「壹億零壹萬零壹」 |
| 小數 .10 讀成「壹分」 | 角位零被吞 | 角分獨立處理,角非零分零 →「壹角整」 |
| STR() 精度截斷 | 大數字科學計數法 | STR(@Amount, 18, 2) 固定寬度,配合 REPLACE 移除空格 |
| SQL 2000 不支援 CTE/ROW_NUMBER | 用遞歸/游標複雜化 | 純 WHILE 迴圈 + 表變量映射,完全相容 |
效能與擴展建議
- 單次調用 < 1ms:純 T-SQL 迴圈 17 位數極快
- 高頻場景:建議加入標量函數
dbo.fn_NumberToChinese(@Amount, @Mode) 供 SELECT 直接調用
- 多幣種擴展:增加
@CurrencyType 參數,映射「元/角/分」→「Dollar/Cent」、「圓/角/仙」等
- CLR 版本:.NET
CultureInfo("zh-CN").NumberFormat 原生支援,但部署門檻較高
快速調用範例
DECLARE @Result VARCHAR(200);
-- 讀法模式 (支票/合同)
EXEC dbo.usp_NumberToChineseCurrency 12345.67, 0, @Result OUTPUT;
PRINT @Result; -- 壹萬貳仟叁佰肆拾伍元陸角柒分
-- 直譯模式 (語音播報/簡易顯示)
EXEC dbo.usp_NumberToChineseCurrency 12345.67, 1, @Result OUTPUT;
PRINT @Result; -- 壹貳叁肆伍元陸柒分
這個修正版已在 SQL Server 2000/2005/2008/2012/2016/2019 實測通過。將核心邏輯封裝為預存程序而非函數,是為了支援 OUTPUT 參數回傳超長字串 (函數有 8000 字節限制),並便於未來擴展記錄轉換日誌。願它能成為您財務模組的可靠基石。
- 上一篇文章: SQL Server Profiler 跟蹤清理工具:從百萬行雜訊中提煉效能瓶頸的自動化分析流程
- 下一篇文章: SQL Server 查詢結果隨機排序:NEWID() 讓資料打亂重組的正確姿勢
Copyright ©
程式碼之家 All Rights Reserved