Please start any new threads on our new site at https://forums.sqlteam.com. We've got lots of great SQL Server experts to answer whatever question you can come up with.

 All Forums
 SQL Server 2000 Forums
 SQL Server Development (2000)
 another simple sql query :)

Author  Topic 

sengoku
Starting Member

29 Posts

Posted - 2003-06-19 : 10:59:11
hello again

thanks for all the help i've been getting on this board, you guys really know your stuff!

anyway, what i'm after now is a function to do this :

take a number with any number of digits, including after the decimal point, and put commas in every 3 digits to the left of the decimal.

so

1.33324 -> 1.33324
1000 -> 1,000
10000.228 -> 10,000.228
100000000 -> 100,000,000

is there such a thing in SQL? i don't want to convert to a money datatype because that seems to round it to 2 decimal places...

thanks in advance

mr_mist
Grunnio

1870 Posts

Posted - 2003-06-19 : 11:03:05
You could do this in SQL, but it's a task that seems better suited to your presentation layer, or reporting tool.

-------
Moo.
Go to Top of Page

macka
Posting Yak Master

162 Posts

Posted - 2003-06-19 : 11:03:31
Why do you need to do this in SQL Server. This is a presentation issue and should be handled from the front-end.

macka.

--
There are only 10 types of people in the world - Those who understand binary, and those who don't.
Go to Top of Page

jsmith8858
Dr. Cross Join

7423 Posts

Posted - 2003-06-19 : 11:04:40
This is a job for the presentation layer, not SQL.

how are you returning this data to the user? i.e., are you using ASP to write HTML or a report program like Access or Crystal? Use the formatting options in those applications.

let me know if this doesn't make sense. SQL is not really designed to handle formatting of data.

- Jeff
Go to Top of Page

jsmith8858
Dr. Cross Join

7423 Posts

Posted - 2003-06-19 : 11:05:12
so, I guess we all agree then !


- Jeff
Go to Top of Page

sengoku
Starting Member

29 Posts

Posted - 2003-06-19 : 11:08:39
hmmm, yes, i know it should be handled by the front end but the way it's been coded this would actually be more work - in this case the front end just takes whatever value is in the database and passes it to a string-parser proc, which slots it into a string for displaying... and as it stands the string-parser has no knowledge about what the data it's displaying is... which would be a bit of work to code in (loads of case statements :))

so, thanks for the ideas, but is there anyway i can achieve this in sql? or am i spitting into the wind? :D

Go to Top of Page

jsmith8858
Dr. Cross Join

7423 Posts

Posted - 2003-06-19 : 11:11:14
What is the front end?

- Jeff
Go to Top of Page

sengoku
Starting Member

29 Posts

Posted - 2003-06-19 : 11:15:04
the front end is asp... but it's set up for easy changing of language, so everything it displays it just like this :

"you have completed the [%1] stage of this process"
"you have made £[%1] from the slug-racing team"
"i think you are a [%1]"

etc etc

and then just does a replace on the [%1] with the results from a varchar field. so as you can see it would be rather more work to do it case-by-case in the asp, and actually easier in this case to do it in the db when it inserts whatever into the varchar field :)

Go to Top of Page

jsmith8858
Dr. Cross Join

7423 Posts

Posted - 2003-06-19 : 12:14:57
hate to say it, but you need to add the functionalilty to your presentation layer.

Like you said, there is a function or procedure in your ASP scripts that put the arguments into the string in place of the [%1] placeholders, and I think you need to add a little more functionality to that script.

For example, right now it just takes the argument and puts it in place of the [%1], but why not have the function handle this case:

[%1, <some format>]

and in the <some format> part you can have some indicator of how it should be formatted.

I would need to see the function that does the current substitution to help you further.



- Jeff
Go to Top of Page

Amethystium
Aged Yak Warrior

701 Posts

Posted - 2003-06-20 : 06:08:52
Here is a function that would format your numbers the way you want.

CREATE FUNCTION DBO.FORMATNUMBER (@VALUE NUMERIC(19,6))
RETURNS VARCHAR(100)
AS
BEGIN
DECLARE @PART1 VARCHAR(100) -- HOLDS ALL THE DIGITS ON THE LEFT OF THE DICMAL PLACE
DECLARE @PART2 VARCHAR(100) -- GOLD ALL DIGITS ON THE RIGHT SIDE OF THE DECIMAL PLACE
DECLARE @HOLDER VARCHAR(100) -- HOLD THE MAIN NUMBER
DECLARE @COUNTER INT -- COUNTER FOR THE WHILE LOOP
DECLARE @FLG INT -- INDICATOR FOR POSITIVE/NEGATIVE NUMBERS

SET @FLG = 0

IF @VALUE < 0
BEGIN
SET @FLG = 1
END

SET @HOLDER = (CONVERT(VARCHAR(100),ABS(@VALUE)))

SET @PART1 = SUBSTRING(@HOLDER, 1, CHARINDEX('.', @HOLDER)-1)
SET @PART1 = REVERSE(@PART1)
SET @PART2 = SUBSTRING(@HOLDER, CHARINDEX('.', @HOLDER),LEN(@HOLDER)-CHARINDEX('.', @HOLDER)+1)

SET @COUNTER = 1
SET @HOLDER = ''

WHILE @COUNTER <= LEN(@PART1)
BEGIN
IF @COUNTER%3 = 0
BEGIN
SELECT @HOLDER = @HOLDER + SUBSTRING(@PART1, @COUNTER, 1)+','
END
ELSE
BEGIN
SELECT @HOLDER = @HOLDER + SUBSTRING(@PART1, @COUNTER, 1)
END
SET @COUNTER = @COUNTER + 1
END

IF SUBSTRING(REVERSE(@HOLDER), 1, 1) = ',' BEGIN SET @HOLDER = SUBSTRING(@HOLDER, 1, LEN(@HOLDER)-1) END

IF @FLG = 1
RETURN '-'+REVERSE(@HOLDER)+CASE WHEN CAST(@PART2 AS NUMERIC(19,4)) = 0 THEN '' ELSE @PART2 END

RETURN REVERSE(@HOLDER)+CASE WHEN CAST(@PART2 AS NUMERIC(19,4)) = 0 THEN '' ELSE @PART2 END

END

Example,

SELECT DBO.FORMATNUMBER(100000000) = 100,000,000
SELECT DBO.FORMATNUMBER(120000.2584) = 120,000.258400

note that I have set the accuracy to 6 decimal places hence the two extra 0s in the second statment.

This will now take care of positive as well as negative numbers. Cheers Misty

Good Luck!

Edited by - Amethystium on 06/20/2003 06:32:26

Edited by - Amethystium on 06/20/2003 10:36:26
Go to Top of Page

mr_mist
Grunnio

1870 Posts

Posted - 2003-06-20 : 06:15:13
Nice function. It has some problems with negative numbers, I don't know if that is a requirement, if so it might need some extra code to handle the -

select dbo.formatnumber (-412)

-,412

select dbo.formatnumber (-126412)

-,126,412

I imagine negatives would need to be converted to a positive number then translated with the commas and then have the - stuck on the front again. Or something.

-------
Moo.
Go to Top of Page

Amethystium
Aged Yak Warrior

701 Posts

Posted - 2003-06-20 : 06:18:47
quote:

Nice function. It has some problems with negative numbers, I don't know if that is a requirement, if so it might need some extra code to handle the -

select dbo.formatnumber (-412)

-,412

select dbo.formatnumber (-126412)

-,126,412

I imagine negatives would need to be converted to a positive number then translated with the commas and then have the - stuck on the front again. Or something.

-------
Moo.



Well spotted Misty.
For some reason I ignored negatives, but I will make the changes now.

Good Luck!
Go to Top of Page

jsmith8858
Dr. Cross Join

7423 Posts

Posted - 2003-06-20 : 08:03:00
Funny, you can write a nice long complex UDF (that only works in SQL Server 2000) that must run on every row and then eventually returns to the client a varchar() instead of the actual number -- which means you can't do math with it, or subtotal it later on, or do any comparisions with it -- or you can do this in your ASP page:

response.write FormatCurrency(r("ColumnName"),2,,true,true)

I'd go with option #2.

I know I sound like a broken record sometimes, but I can stress enough how you should not spend any time writing SQL code to do formatting ... just return the results.

- Jeff

Edited by - jsmith8858 on 06/20/2003 08:10:32
Go to Top of Page

Page47
Master Smack Fu Yak Hacker

2878 Posts

Posted - 2003-06-20 : 08:29:11
Fun with tally tables ...

declare @n decimal(20,8), @c varchar(20)
select @n = -417543678.2425

select
@c = coalesce(@c,'') + m
from (
select top 100 percent
n,
case
when n%10 = 0 then substring(convert(varchar,@n),n/10,1)
when (n/10) < charindex('.',convert(varchar,@n))-1 and
((n/10) - charindex('.',convert(varchar,@n))+1)%3=0 and
n%5 = 0 and
substring(convert(varchar,@n),(n/10),1) <> '-' then ','
else null
end as m
from
dbo.tally
where
n/10<=len(convert(varchar,@n)) and
n >= 10
order by
n) n
where
m is not null
order by
n

select @c

 


Jay White
{0}
Go to Top of Page

Amethystium
Aged Yak Warrior

701 Posts

Posted - 2003-06-20 : 08:38:10
That is wicked Page47. Nicely done sir.

Tally... tally.. tally... telly..

I never know how/when to use them.

P.S.
Some weird stuff about number 47. Intersting website I have to say.

Good Luck!
Go to Top of Page

Page47
Master Smack Fu Yak Hacker

2878 Posts

Posted - 2003-06-20 : 08:58:34
I should note that in this case I completely agree with Jeff and others that formatting is the job of the presentation layer ... I just saw the function and had to write a set-based version

Jay White
{0}
Go to Top of Page

jsmith8858
Dr. Cross Join

7423 Posts

Posted - 2003-06-20 : 09:03:04
very nice, Jay ...

not to be picky, but I hope we all know that in cases like this the set-based method would be much slower than a simple iterative loop .... you shouldn't add I/O or access to database tables to a UDF if it doesn't need it.

having said that, it is definitely a cool solution !


- Jeff

Edited by - jsmith8858 on 06/20/2003 09:03:25
Go to Top of Page

Amethystium
Aged Yak Warrior

701 Posts

Posted - 2003-06-20 : 09:17:39
quote:

I should note that in this case I completely agree with Jeff and others that formatting is the job of the presentation layer ... I just saw the function and had to write a set-based version

Jay White
{0}



In other words, my UDF sucks right?

P.S.
I just saw your profile Page47. My uncle lives in the same area!

Edited by - Amethystium on 06/20/2003 09:20:44
Go to Top of Page

Page47
Master Smack Fu Yak Hacker

2878 Posts

Posted - 2003-06-20 : 10:01:27
No, actually, mine sucks ...

Consider a tally table with 1000 rows ...

declare @t datetime
set @t = getdate()
--my version of the function
select dbo.formatnumber2(rand(convert(binary(4),newid()))* t1.n * 10000) from tally t1
select datediff(ms,@t,getdate())
set @t = getdate()
select dbo.formatnumber(rand(convert(binary(4),newid()))* t1.n * 10000) from tally t1
select datediff(ms,@t,getdate())

 
Mine is taking about 1300 ms to format 1000 random numbers ... yours seems to do the same job in about 60 ms ...

Jay White
{0}
Go to Top of Page

jsmith8858
Dr. Cross Join

7423 Posts

Posted - 2003-06-20 : 10:02:41
nothing is wrong with the UDF at all ... it technically works fine, it is just that choosing to solve this particular problem (or any formatting problem for that matter) within SQL server is NOT a good way to do it ... do it at the presentation layer.

- Jeff
Go to Top of Page

Amethystium
Aged Yak Warrior

701 Posts

Posted - 2003-06-20 : 10:22:56
quote:

nothing is wrong with the UDF at all ... it technically works fine, it is just that choosing to solve this particular problem (or any formatting problem for that matter) within SQL server is NOT a good way to do it ... do it at the presentation layer.

- Jeff



I guess that is something that I am beginning to realise more and more as I learn more about SQL Server. Cosmetic issues should be left to the presentation layer as you put it. Good advice if you ask me, still, it was fun writing the UDF.

Good Luck!
Go to Top of Page
    Next Page

- Advertisement -