March 4, 2009 at 10:17 pm
I have a task like number(digits) to word format
example 1900 =thousand and nine hundred
if i using this type it takes very lengthy coding..
what i do
My attempt like this..
create PROCEDURE NUMTOWORD
@INPUT AS BIGINT
AS
BEGIN
IF(LEN(@INPUT) = 1)
SELECT CASE @INPUT
WHEN 1 THEN 'ONE'
WHEN 2 THEN 'TWO'
WHEN 3 THEN 'THREE'
WHEN 4 THEN 'FOUR'
WHEN 5 THEN 'FIVE'
WHEN 6 THEN 'SIX'
WHEN 7 THEN 'SEVEN'
WHEN 8 THEN 'EIGHT'
WHEN 9 THEN 'NINE'
WHEN 0 THEN 'ZERO'
ELSE '**' END
ELSE IF(LEN(@INPUT) = 2)
PRINT 'EXCEED'
END
GO
March 5, 2009 at 11:16 am
First, you should be warned that string manipulations like this should be done by the application, not in SQL. The reasons for this are to protect the SQL Server from the calculation load and to minimize the data being transported over the network. That said, if you MUST do it in SQL, the following code is an example of how it can be done.
If this is going to be a regular occurrence in your system, I would suggest using the above code to create a permanent table consisting of two columns. The first column would be a primary key consisting only of the integers for the range where you might use this. The second column would contain the full text of the number in words. You can then easily join to this table whenever you have to do the conversion. I suspect it will also run much faster, but I can't test that until later today. When I have a chance I will post up the code and the results.
Please let me know if you have any questions.
declare @sample int
set @sample = 1919
declare @numwords table(number int, ones varchar(15), tens varchar(15), hundreds varchar(15), thousands varchar(15))
insert into @numwords
select 0,'','','','' union all
select 1,'One','Ten','One Hundred','One Thousand' union all
select 2,'Two','Twenty','Two Hundred','Two Thousand' union all
select 3,'Three','Thirty','Three Hundred','Three Thousand' union all
select 4,'Four','Forty','Four Hundred','Four Thousand' union all
select 5,'Five','Fifty','Five Hundred','Five Thousand' union all
select 6,'Six','Sixty','Six Hundred','Six Thousand' union all
select 7,'Seven','Seventy','Seven Hundred','Seven Thousand' union all
select 8,'Eight','Eighty','Eight Hundred','Eight Thousand' union all
select 9,'Nine','Ninety','Nine Hundred','NineThousand' union all
select 10,'Nineteen','','','' union all
select 11,'Eleven','','','' union all
select 12,'Twelve','','','' union all
select 13,'Thirteen','','','' union all
select 14,'Fourteen','','','' union all
select 15,'Fifteen','','','' union all
select 16,'Sixteen','','','' union all
select 17,'Seventeen','','','' union all
select 18,'Eighteen','','','' union all
select 19,'Nineteen','','',''
select max(case when number = substring(reverse(@sample),4,1) then thousands else '' end)
,max(case when number = substring(reverse(@sample),3,1) then hundreds else '' end)
,max(case when right(@sample,2) not between 11 and 19 and number = substring(reverse(@sample),2,1) then tens else '' end)
,max(case when right(@sample,2) not between 11 and 19 and number = right(@sample,1) then ones
when right(@sample,2) between 11 and 19 and number = right(@sample,2) then ones
else '' end)
,max(right(@sample,2))/*and number = substring(reverse(@sample),2,1) <> 1 then ones
when substring(reverse(@sample),2,1) = 1 and number = right(@sample,2) then ones
else '' end) */
from @Numwords
__________________________________________________
Against stupidity the gods themselves contend in vain. -- Friedrich Schiller
Stop, children, what's that sound? Everybody look what's going down. -- Stephen Stills
March 5, 2009 at 2:01 pm
March 5, 2009 at 2:07 pm
Once the table is built it appears to be more efficient to just look a number up. Running the test below with 9999 different numbers, the join to the existing table takes about 200 ms elapsed time and the version which builds the string on the fly runs in over 1300 ms. The difference in CPU time is MUCH greater. However, there may be much faster ways to build the string than the solution I threw together. If I find one that runs faster than simply looking the string up by means of a join to a prepopulated table, I will post it here.
declare @numwords table(number int, ones varchar(15), tens varchar(15), hundreds varchar(15), thousands varchar(15))
insert into @numwords
select 0,NULL,NULL,NULL,NULL union all
select 1,'One','Ten','One Hundred','One Thousand' union all
select 2,'Two','Twenty','Two Hundred','Two Thousand' union all
select 3,'Three','Thirty','Three Hundred','Three Thousand' union all
select 4,'Four','Forty','Four Hundred','Four Thousand' union all
select 5,'Five','Fifty','Five Hundred','Five Thousand' union all
select 6,'Six','Sixty','Six Hundred','Six Thousand' union all
select 7,'Seven','Seventy','Seven Hundred','Seven Thousand' union all
select 8,'Eight','Eighty','Eight Hundred','Eight Thousand' union all
select 9,'Nine','Ninety','Nine Hundred','NineThousand' union all
select 10,'Nineteen',NULL,NULL,NULL union all
select 11,'Eleven',NULL,NULL,NULL union all
select 12,'Twelve',NULL,NULL,NULL union all
select 13,'Thirteen',NULL,NULL,NULL union all
select 14,'Fourteen',NULL,NULL,NULL union all
select 15,'Fifteen',NULL,NULL,NULL union all
select 16,'Sixteen',NULL,NULL,NULL union all
select 17,'Seventeen',NULL,NULL,NULL union all
select 18,'Eighteen',NULL,NULL,NULL union all
select 19,'Nineteen',NULL,NULL,NULL
set statistics time on;
with expanded as
(select N
,max(case when number = substring(reverse(N),4,1) then thousands else '' end) as thousands
,max(case when number = substring(reverse(N),3,1) then hundreds else '' end) as hundreds
,max(case when right(N,2) not between 11 and 19 and number = substring(reverse(N),2,1) then tens else '' end) as tens
,max(case when right(N,2) not between 11 and 19 and number = right(N,1) then ones
when right(N,2) between 11 and 19 and number = right(N,2) then ones
else '' end) as ones
from @Numwords
cross join dbo.Tally
group by N
)
select N,isnull(thousands+' ','')+isnull(hundreds+' ','')+isnull(tens+' ','')+isnull(ones,'')
from expanded
where N <= 9999
set statistics time off;
-- create a temp table to test lookup
create table #numwords (number int primary key, words varchar(200))
;with expanded as
(select N
,max(case when number = substring(reverse(N),4,1) then thousands else '' end) as thousands
,max(case when number = substring(reverse(N),3,1) then hundreds else '' end) as hundreds
,max(case when right(N,2) not between 11 and 19 and number = substring(reverse(N),2,1) then tens else '' end) as tens
,max(case when right(N,2) not between 11 and 19 and number = right(N,1) then ones
when right(N,2) between 11 and 19 and number = right(N,2) then ones
else '' end) as ones
from @Numwords
cross join dbo.Tally
group by N
)
insert into #numwords
select N,isnull(thousands+' ','')+isnull(hundreds+' ','')+isnull(tens+' ','')+isnull(ones,'')
from expanded
where N <= 9999
--select * from #numwords
set statistics time on;
-- test using join to existing table
select t.N,nw.words
from dbo.tally t
join #numwords nw on t.N = nw.Number
set statistics time off;
-- test join with set of 9999 random numbers
create table #testSet (testnum int)
insert into #testset
select ABS(CHECKSUM(NEWID())) % 9998 + 1
from dbo.tally
where N < 10000
set statistics time on;
-- test using join to existing table
select t.testnum,nw.words
from #testSet t
join #numwords nw on t.testNum = nw.Number
set statistics time off;
drop table #numwords
drop table #testSet
__________________________________________________
Against stupidity the gods themselves contend in vain. -- Friedrich Schiller
Stop, children, what's that sound? Everybody look what's going down. -- Stephen Stills
March 5, 2009 at 2:37 pm
In addition to Bob Hovious code you might want to read this article by Anthony Zarkin
which includes all the necessary code to create user functions to convert numbers
to words and queries to test the results.
http://www.sqlservercentral.com/scripts/function/65640/
I the case of your example the return would be:
One Thousand Nine Hundred
March 5, 2009 at 2:53 pm
I just tested the function from that article ... it is SLOW!!!!
9999 rows converted using that function takes almost 20 seconds!!!
set statistics time on;
-- test using join to existing table
select t.testnum,nw.words
from #testSet t
join #numwords nw on t.testNum = nw.Number
set statistics time off;
(9999 row(s) affected)
SQL Server Execution Times:
CPU time = 32 ms, elapsed time = 235 ms.
set statistics time on;
-- test using the user function from the article
select testnum,dbo.fnSpellInteger(testNum)
from #testSet
set statistics time off;
(9999 row(s) affected)
SQL Server Execution Times:
CPU time = 19218 ms, elapsed time = 19916 ms.
__________________________________________________
Against stupidity the gods themselves contend in vain. -- Friedrich Schiller
Stop, children, what's that sound? Everybody look what's going down. -- Stephen Stills
March 5, 2009 at 3:07 pm
Bob Hovious (3/5/2009)
I just tested the function from that article ... it is SLOW!!!!9999 rows converted using that function takes almost 20 seconds!!!
Heh... I absolutely love it... let me officially welcome you to the "Doubting Thomas Club for SQL". Our motto is "Make it work, make it fast, make it pretty... and it ain't done 'til it's pretty!" Well done!
--Jeff Moden
Change is inevitable... Change for the better is not.
March 5, 2009 at 3:12 pm
Thanks Jeff... I take more pride in a compliment like that from you than I would from an MVP.... although unfortunately it doesn't look as good on a resume. π
You know of course that I'm still going to come gunning for you occasionallly like some punk gunslinger out to make a rep. :w00t:
__________________________________________________
Against stupidity the gods themselves contend in vain. -- Friedrich Schiller
Stop, children, what's that sound? Everybody look what's going down. -- Stephen Stills
March 5, 2009 at 3:16 pm
Bob, How does it compares with Steve's Solution ?
* Noel
March 5, 2009 at 3:23 pm
Steve posted his times for 11000 rows as follows
SQL Server Execution Times:
CPU time = 4992 ms, elapsed time = 5213 ms.
When I tested it on my box at 9999 rows to get apples to apples, the results were still not good.
set statistics time on;
-- test using join to existing table
select t.testnum,nw.words
from #testSet t
join #numwords nw on t.testNum = nw.Number
set statistics time off;
(9999 row(s) affected)
SQL Server Execution Times:
CPU time = 31 ms, elapsed time = 230 ms.
set statistics time on;
-- test using Steve's user function from the discussion of the article
select testnum,dbo.fnSpellIntegerSteve(testNum)
from #testSet
set statistics time off;
(9999 row(s) affected)
SQL Server Execution Times:
CPU time = 16938 ms, elapsed time = 17873 ms.
SQL is just really, REALLY good at looking stuff up.
__________________________________________________
Against stupidity the gods themselves contend in vain. -- Friedrich Schiller
Stop, children, what's that sound? Everybody look what's going down. -- Stephen Stills
March 5, 2009 at 3:50 pm
Jeff Moden (3/5/2009)
Bob Hovious (3/5/2009)
I just tested the function from that article ... it is SLOW!!!!9999 rows converted using that function takes almost 20 seconds!!!
Heh... I absolutely love it... let me officially welcome you to the "Doubting Thomas Club for SQL". Our motto is "Make it work, make it fast, make it pretty... and it ain't done 'til it's pretty!" Well done!
Hey Jeff Unless my beer is speaking for me, there was a very similar exercise a few months ago...I'm gonna look, if only 'cos it was so much fun then! π
For fast, accurate and documented assistance in answering your questions, please read this article.
Understanding and using APPLY, (I) and (II) Paul White
Hidden RBAR: Triangular Joins / The "Numbers" or "Tally" Table: What it is and how it replaces a loop Jeff Moden
March 5, 2009 at 4:02 pm
Bob Hovious (3/5/2009)
Thanks Jeff... I take more pride in a compliment like that from you than I would from an MVP.... although unfortunately it doesn't look as good on a resume. πYou know of course that I'm still going to come gunning for you occasionallly like some punk gunslinger out to make a rep. :w00t:
Heh... You DID get the compliment from an MVP.... I got the MVP award last July... I just don't brag about it and they wanted a bit too much information than I was comfortable with on the MVP website.
--Jeff Moden
Change is inevitable... Change for the better is not.
March 5, 2009 at 4:05 pm
Chris Morris (3/5/2009)
Jeff Moden (3/5/2009)
Bob Hovious (3/5/2009)
I just tested the function from that article ... it is SLOW!!!!9999 rows converted using that function takes almost 20 seconds!!!
Heh... I absolutely love it... let me officially welcome you to the "Doubting Thomas Club for SQL". Our motto is "Make it work, make it fast, make it pretty... and it ain't done 'til it's pretty!" Well done!
Hey Jeff Unless my beer is speaking for me, there was a very similar exercise a few months ago...I'm gonna look, if only 'cos it was so much fun then! π
If it looks like you're seeing double or triple when you find them, don't worry... it's not the beer. There have been many such exercises in the last couple of months... some I participated in, some not. π
--Jeff Moden
Change is inevitable... Change for the better is not.
March 5, 2009 at 4:16 pm
You DID get the compliment from an MVP
I heard you were an MVP. What I meant to say was that I took more pride in that compliment than in BEING an MVP. From what I heard recently, starting a blog and making some posts on the right forums would get me in like Flynn, whether or not the posts were up to SSC standards. :hehe:
__________________________________________________
Against stupidity the gods themselves contend in vain. -- Friedrich Schiller
Stop, children, what's that sound? Everybody look what's going down. -- Stephen Stills
March 5, 2009 at 6:08 pm
Bob Hovious (3/5/2009)
You DID get the compliment from an MVP
I heard you were an MVP. What I meant to say was that I took more pride in that compliment than in BEING an MVP. From what I heard recently, starting a blog and making some posts on the right forums would get me in like Flynn, whether or not the posts were up to SSC standards. :hehe:
BWAA-HAA!!! That would be true in many cases... all part of the reason I haven't finished my online registration for it... I'm not too happy with many of the folks that get/have the MVP and the incidents you're talking about are proof of that.
--Jeff Moden
Change is inevitable... Change for the better is not.
Viewing 15 posts - 1 through 15 (of 18 total)
You must be logged in to reply to this topic. Login to reply