我正在寻找基于recursive CTE(公用表表达式)解决方案的简单脚本或函数,用于在T-SQL中将整数转换为英文单词。递归CTE速度很快,尤其是在内联表值函数中使用时,并且易于理解和维护。另外,它应该在整个BIGINT范围内运行(尽管我不在乎否定值),即从0到2 64 -1。
编辑:例如,如果将递归CTE放在标量函数中(用于说明):SELECT dbo.NumberToWords(0)
应该返回字符串'zero'; SELECT dbo.NumberToWords(1234)
应该返回非常类似于“一千零二十四”或“一千二百三十四”的内容;依此类推,对于BIGINT范围内的所有数字,
我见过的大多数其他(过程性)解决方案都很慢,崩溃导致大数目,或者对于某些输入(例如,一百万),返回纯错误或无结果。
我知道那里还有很多其他程序解决方案;我特别想要递归CTE。据我所知,目前还没有这样的解决方案。
答案 0 :(得分:4)
这会将BIGINT范围内的非负数转换为英文单词。
CREATE FUNCTION dbo.tvfNumberToEnglishWords (@Number BIGINT) -- BIGINT is 64 bit signed integer
-- Converts whole numbers into English words. Returns an empty string for negative numbers.
-- Parameter @Number is a 64-bit signed integer, which allows a range of zero to 9,223,372,036,854,775,807
-- 2018-08-29 - Dave Boltman - Created
RETURNS TABLE AS
RETURN
WITH
Smalls AS (
SELECT n, Name
FROM (VALUES (1, 'one'), (2, 'two'), (3, 'three'), (4, 'four'), (5, 'five'), (6, 'six'), (7, 'seven'),
(8, 'eight'), (9, 'nine'), (10, 'ten'), (11, 'eleven'), (12, 'twelve'), (13, 'thirteen'), (14, 'fourteen'),
(15, 'fifteen'), (16, 'sixteen'), (17, 'seventeen'), (18, 'eighteen'), (19, 'nineteen')) AS s (n, Name)
),
Decades AS (
SELECT n, Name
FROM (VALUES (2, 'twenty'), (3, 'thirty'), (4, 'forty'), (5, 'fifty'),
(6, 'sixty'), (7, 'seventy'), (8, 'eighty'), (9, 'ninety')) AS t (n, Name)
),
Groups AS (
SELECT n, Name
FROM (VALUES (0, ''), (1, ' thousand'), (2, ' million'), (3, ' billion'), (4, ' trillion'), (5, ' quadrillion'), (6, ' quintillion')
-- up to here is enough for 64 bit integers
) AS g (n, Name)
),
cte AS (
-- Level 0 : Anchor query to start the processing
SELECT
CAST (0 AS INT) AS Level,
CAST (@Number % 1000 AS BIGINT) Lowest3Digits,
cast (@Number / 1000 AS BIGINT) AS RemainingDigits,
CASE WHEN @Number = 0 THEN CAST ('zero' AS VARCHAR(1024)) ELSE '' END TextSoFar
UNION ALL
-- Recursive query based on the previous level
SELECT
Level + 1 AS Level, -- increase the level
RemainingDigits % 1000 AS Lowest3Digits,
RemainingDigits / 1000 AS RemainingDigits,
-- Busniess part is here
CAST (
CASE WHEN (RemainingDigits > 0) AND (Lowest3Digits > 0)
THEN CASE WHEN (Hundreds > 0) OR (Level > 0) THEN ', ' ELSE ' and ' END -- change ' and ' to ' ' for American English
ELSE ''
END
+ CASE WHEN Hundreds > 0 THEN (SELECT Name FROM Smalls WHERE n = Hundreds) + ' hundred' ELSE '' END
+ CASE WHEN (Hundreds > 0) AND (TensUnits > 0) THEN ' and ' ELSE '' END
+ CASE WHEN TensUnits >= 20
THEN (SELECT Name FROM Decades WHERE n = Tens)
+ CASE WHEN Units > 0 THEN (SELECT '-' + Name FROM Smalls WHERE n = Units) ELSE '' END
ELSE CASE WHEN TensUnits > 0 THEN (SELECT Name FROM Smalls WHERE n = TensUnits) ELSE '' END
END
+ CASE WHEN Lowest3Digits > 0 THEN (SELECT Name FROM Groups WHERE n = Level) ELSE '' END
+ TextSoFar
AS VARCHAR(1024)) AS TextSoFar
FROM
( SELECT Level, Lowest3Digits, RemainingDigits, TextSoFar,
Lowest3Digits / 100 AS Hundreds, Lowest3Digits % 100 AS TensUnits, (Lowest3Digits % 100) / 10 AS Tens, Lowest3Digits % 10 AS Units
FROM cte -- Dave Boltman made this code
) AS l
WHERE -- condition for exiting the recursion
(Lowest3Digits > 0) OR (RemainingDigits > 0)
)
SELECT TOP 1 TextSoFar AS EnglishText FROM cte ORDER BY Level DESC
GO
有限的测试数据
SELECT n, dbo.fnNumberToEnglishWords(n) AS AsText
FROM (VALUES (0),(-1),(1),(19),(63),(100),(101),(147),(1000),(1001),(1056),(1100),(1110),(900456),(76543),(1000000),(1000001),(1001001),(1001000),(1234567),(1234567890),(9223372036854775807)) x (n)
结果
n AsText
--------------------- ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
0 zero
-1
1 one
19 nineteen
63 sixty-three
100 one hundred
101 one hundred and one
147 one hundred and forty-seven
1000 one thousand
1001 one thousand and one
1056 one thousand and fifty-six
1100 one thousand, one hundred
1110 one thousand, one hundred and ten
900456 nine hundred thousand, four hundred and fifty-six
76543 seventy-six thousand, five hundred and forty-three
1000000 one million
1000001 one million and one
1001001 one million, one thousand and one
1001000 one million, one thousand
1234567 one million, two hundred and thirty-four thousand, five hundred and sixty-seven
1234567890 one billion, two hundred and thirty-four million, five hundred and sixty-seven thousand, eight hundred and ninety
9223372036854775807 nine quintillion, two hundred and twenty-three quadrillion, three hundred and seventy-two trillion, thirty-six billion, eight hundred and fifty-four million, seven hundred and seventy-five thousand, eight hundred and seven
编辑 :(移至此处)使用当前的英式英语。如果您喜欢美式英语,只需将上面的字符串文字之一从' and '
更改为' '
(代码中有描述方式的注释)。所谓 current 英式英语,是指short scale一直在美式英语中使用(即“十亿”表示1,000,000,000),而不是较旧的长期使用语言(直到大约在70年代,“十亿”表示一百万或一万亿)。
我在结果中包括了逗号,尽管我不确定这是否是标准的。如果不想,只需删除字符串文字中的逗号即可。