65.9K
CodeProject 正在变化。 阅读更多。
Home

金额转文字

starIconstarIconstarIconstarIconstarIcon

5.00/5 (4投票s)

2016年12月16日

CPOL

2分钟阅读

viewsIcon

8718

downloadIcon

98

将金额转换为口语化表达

引言

有时,应用程序需要用文字显示金额。 有很多关于如何在多种编程或脚本语言中执行此操作的示例,但没有一个是在数据库中使用纯 SQL 来执行此操作的示例。 此示例使用德语,但可以轻松地适应任何其他语言。

背景

将金额转换为文字的问题在于,口头表达不会简单地连接每个数字的单词,而是会在其中填充一些额外的单词 - 而且一些口头数字的说法取决于它们的位置。 例如,在德语中,数字 7 的发音是Sieben,但 17 不是Siebenzehn,而是Siebzehn,而 117 将发音为Einhundertsiebzehn,而不是EinsZehnSiebenEinsSiebenzehn

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一词来代替TensTens的部分设置为文字表达式的末尾,因为在口头表达时,它们将以Ones为前缀(例如,Dreizehn而不是ZehnDrei)。

您可以从附加到此技巧/窍门的 ZIP 存档中下载 3 个 SQL 函数。

如果您需要另一种语言、更大的金额范围或更多的小数位,我相信您会很容易地将此示例调整到您的需求。

玩得开心!

© . All rights reserved.