金额转文字





5.00/5 (4投票s)
将金额转换为口语化表达
引言
有时,应用程序需要用文字显示金额。 有很多关于如何在多种编程或脚本语言中执行此操作的示例,但没有一个是在数据库中使用纯 SQL 来执行此操作的示例。 此示例使用德语,但可以轻松地适应任何其他语言。
背景
将金额转换为文字的问题在于,口头表达不会简单地连接每个数字的单词,而是会在其中填充一些额外的单词 - 而且一些口头数字的说法取决于它们的位置。 例如,在德语中,数字 7 的发音是Sieben
,但 17 不是Siebenzehn
,而是Siebzehn
,而 117 将发音为Einhundertsiebzehn
,而不是EinsZehnSieben
或EinsSiebenzehn
。
Using the Code
此解决方案使用 3 个 SQL 函数来完成所有工作。
要转换 -9999999999999999.99 到 +9999999999999999.99 之间的任何数字,只需调用
SELECT [dbo].[Amount2Words] (-123456.07)
// (returns 'MinusEinhundertdreiundzwanzigtausendvierhundertsechsundfünfzigKommaNullSieben')
这是主函数代码
CREATE FUNCTION [dbo].[Amount2Words]
(
@Amount numeric(18,2)
)
RETURNS nvarchar(255)
AS
BEGIN
DECLARE @bolNegative bit = 0;
DECLARE @strAmount nvarchar(255);
DECLARE @intAmount bigint = 0;
DECLARE @intDecimals int = 0;
DECLARE @intHundreds int = 0;
DECLARE @strEntity nvarchar(10);
DECLARE @intLoop int = 1;
DECLARE @strAmountInWords nvarchar(255) = '';
IF (@Amount IS NOT NULL)
BEGIN
IF (@Amount BETWEEN -9999999999999999.99 AND 9999999999999999.99)
BEGIN
IF (@Amount < 0)
BEGIN
SET @bolNegative = 1;
SET @Amount = (@Amount * -1);
END
SET @intAmount = CAST(@Amount AS bigint);
SET @intDecimals = ((@Amount - @intAmount) * 100);
SET @strAmount = CAST(@intAmount AS nvarchar(255));
WHILE (LEN(@strAmount) > 0)
BEGIN
IF (LEN(@strAmount) > 3)
BEGIN
SET @intHundreds = CAST(RIGHT(@strAmount, 3) AS int);
SET @strAmount = SUBSTRING(@strAmount, 1, (LEN(@strAmount) - 3));
END
ELSE
BEGIN
SET @intHundreds = @strAmount;
SET @strAmount = '';
END
IF (@intLoop = 1)
SET @strAmountInWords = [dbo].[Hundreds2Words] (@intHundreds, '');
IF (@intLoop = 2)
SET @strAmountInWords = ([dbo].[Hundreds2Words] (@intHundreds, _
'tausend') + @strAmountInWords);
IF (@intLoop > 2)
BEGIN
IF (@intHundreds = 1)
BEGIN
IF (@intLoop = 3)
SET @strEntity = 'million';
IF (@intLoop = 4)
SET @strEntity = 'milliarde';
IF (@intLoop = 5)
SET @strEntity = 'billion';
END
ELSE
BEGIN
IF (@intLoop = 3)
SET @strEntity = 'millionen';
IF (@intLoop = 4)
SET @strEntity = 'milliarden';
IF (@intLoop = 5)
SET @strEntity = 'billionen';
END
SET @strAmountInWords = ([dbo].[Hundreds2Words] _
(@intHundreds, @strEntity) + @strAmountInWords);
END
SET @intLoop = (@intLoop + 1);
END
IF (LEN(@strAmountInWords) = 0)
SET @strAmountInWords = 'Null';
SET @strAmountInWords = (@strAmountInWords + 'Komma');
SET @strAmountInWords = (@strAmountInWords + [dbo].[Decimals2Words] _
(@intDecimals));
IF (LEN(@strAmountInWords) > 0)
SET @strAmountInWords = UPPER(SUBSTRING(@strAmountInWords, 1, 1)) _
+ SUBSTRING(@strAmountInWords, 2, 3999);
IF (@bolNegative = 1)
SET @strAmountInWords = 'Minus' + @strAmountInWords;
END
ELSE
SET @strAmountInWords = '(Fehler!)';
END
RETURN @strAmountInWords;
END
正如您所看到的,该函数接受金额参数作为numeric(18,2)
类型,并将首先检查金额是否为负数,并在转换后在结果文字表达式之前添加一个Minus
(如果需要)。 然后,将 2 个小数位分开,因为它们需要不同的处理。 在WHILE
循环中,金额的整数部分将被分成最多 3 位数字(称为hundreds
)的组,从最右端开始。 这使我们能够确定所属的实体(千、百万等)。 子函数[Hundreds2Words]
将被每个数百组调用,并将实体作为第二个参数 (Suffix
)。 最后,小数部分将使用子函数[Decimals2Words]
格式化,结果将添加到结果表达式的末尾,并用关键字Komma
分隔,以表示以下的小数部分。
两个子函数的工作方式类似,通过将传递的值(hundreds
为 3 位数字,decimals
为 2 位数字)分成数百位计数器、十位计数器和个位计数器,在另一个WHILE
循环中实现。
WHILE (@Hundreds > 0)
BEGIN
IF (@Hundreds >= 100)
BEGIN
SET @intHundreds = (@intHundreds + 1);
SET @Hundreds = (@Hundreds - 100);
END
ELSE
BEGIN
IF (@Hundreds >= 10)
BEGIN
SET @intTens = (@intTens + 1);
SET @Hundreds = (@Hundreds - 10);
END
ELSE
BEGIN
SET @intOnes = @Hundreds;
SET @Hundreds = 0;
END
END
END
请注意,@Hundreds
代表传递给函数的值,而计数器以@int
开头...!
最后,我们使用一些CASE
开关将找到的数字计数器转换为文字
SET @Result = CASE @intHundreds
WHEN 1 THEN 'einhundert'
WHEN 2 THEN 'zweihundert'
WHEN 3 THEN 'dreihundert'
WHEN 4 THEN 'vierhundert'
WHEN 5 THEN 'fünfhundert'
WHEN 6 THEN 'sechshundert'
WHEN 7 THEN 'siebenhundert'
WHEN 8 THEN 'achthundert'
WHEN 9 THEN 'neunhundert'
ELSE ''
END
+ CASE
WHEN (@intOnes = 0) THEN ''
WHEN (@intOnes = 1) AND (@intTens = 0) AND (@Suffix = 'tausend') THEN 'ein'
WHEN (@intOnes = 1) AND (@intTens = 0) AND (Len(@Suffix) > 0) _
AND (@Suffix <> 'tausend') THEN 'eine'
WHEN (@intOnes = 1) AND (@intTens = 0) AND (Len(@Suffix) = 0) THEN 'eins'
WHEN (@intOnes = 1) AND (@intTens = 1) THEN 'elf'
WHEN (@intOnes = 1) AND (@intTens > 1) THEN 'einund'
WHEN (@intOnes = 2) AND (@intTens = 0) THEN 'zwei'
WHEN (@intOnes = 2) AND (@intTens = 1) THEN 'zwölf'
WHEN (@intOnes = 2) AND (@intTens > 1) THEN 'zweiund'
WHEN (@intOnes = 3) AND (@intTens <= 1) THEN 'drei'
WHEN (@intOnes = 3) AND (@intTens > 1) THEN 'dreiund'
WHEN (@intOnes = 4) AND (@intTens <= 1) THEN 'vier'
WHEN (@intOnes = 4) AND (@intTens > 1) THEN 'vierund'
WHEN (@intOnes = 5) AND (@intTens <= 1) THEN 'fünf'
WHEN (@intOnes = 5) AND (@intTens > 1) THEN 'fünfund'
WHEN (@intOnes = 6) AND (@intTens = 0) THEN 'sechs'
WHEN (@intOnes = 6) AND (@intTens = 1) THEN 'sech'
WHEN (@intOnes = 6) AND (@intTens > 1) THEN 'sechsund'
WHEN (@intOnes = 7) AND (@intTens = 0) THEN 'sieben'
WHEN (@intOnes = 7) AND (@intTens = 1) THEN 'sieb'
WHEN (@intOnes = 7) AND (@intTens > 1) THEN 'siebenund'
WHEN (@intOnes = 8) AND (@intTens <= 1) THEN 'acht'
WHEN (@intOnes = 8) AND (@intTens > 1) THEN 'achtund'
WHEN (@intOnes = 9) AND (@intTens <= 1) THEN 'neun'
WHEN (@intOnes = 9) AND (@intTens > 1) THEN 'neunund'
ELSE ''
END
+ CASE
WHEN (@intTens = 1) AND (@intOnes IN (1, 2)) THEN ''
WHEN (@intTens = 1) AND (@intOnes NOT IN (1, 2)) THEN 'zehn'
WHEN (@intTens = 2) THEN 'zwanzig'
WHEN (@intTens = 3) THEN 'dreissig'
WHEN (@intTens = 4) THEN 'vierzig'
WHEN (@intTens = 5) THEN 'fünfzig'
WHEN (@intTens = 6) THEN 'sechzig'
WHEN (@intTens = 7) THEN 'siebzig'
WHEN (@intTens = 8) THEN 'achtzig'
WHEN (@intTens = 9) THEN 'neunzig'
ELSE ''
END;
请参阅对值 1 和 2 的Ones
以及与Tens
的值 1 结合使用的特殊处理,在某些情况下需要特殊处理! 小数的处理方式类似,但如果计数器为0
,则将包含Null
一词来代替Tens
。 Tens
的部分设置为文字表达式的末尾,因为在口头表达时,它们将以Ones
为前缀(例如,Dreizehn
而不是ZehnDrei
)。
您可以从附加到此技巧/窍门的 ZIP 存档中下载 3 个 SQL 函数。
如果您需要另一种语言、更大的金额范围或更多的小数位,我相信您会很容易地将此示例调整到您的需求。
玩得开心!