views:

202

answers:

3

We store a decimal(9,8) in our database. It can have any number of places after the decimal point (well, no more than 8). I am frustrated because I want to display it as human-readable text as part of a larger string created on the server. I want as many decimals to the right of the decimal point as are non-zero, for example:

0.05
0.12345
3.14159265

Are all good

If I do

CAST(d AS varchar(50)) 

I get formatting like:

0.05000000
0.12345000
3.14159265

I get similar output if I cast/convert to a float or other type before casting to a varchar. I know how to do a fixed number of decimal places, such as:

0.050
0.123
3.142

But that is not what I want.

Yes, I know I can do this through complicated string manipulation (REPLACE, etc), there should be a good way to do it.

+1  A: 

Playing around (sql server) i find that casting to float first makes the trick ..

select cast( cast(0.0501000 as float) as varchar(50) )

yields

0.0501

Gaby
This works as you wrote it, but not with the data from my table. I will post back once I know why.
Brad
"3.14159265" returns "3.14159" with this approach. I'd also be concerned about the approximate nature of floats, which may not be able to fully represent the decimals
AdaTheDev
Working now, just a typo, still has the problem AdaTheDev reported (not an issue for me, but could be for others)
Brad
@AdaTheDev, you are correct.. i did not test with larger data than my example..
Gaby
A: 

For anything other than fairly straight forward manipulation, I'd be considering doing this in your calling code instead tbh as I think it's usually best for SQL to return the data as-is from the database, and then leave the formatting of that up to whatever is calling it, which is more than likely better geared up for string manipulation. Especially if you find yourself jumping though hoops to try to achieve it.

AdaTheDev
As I said in my post, the calling code is expecting a string. Depending on other data in the database, this number may or may not even be part of that string.
Brad
A: 

Code copied almost verbatim from here (also discusses the 6-digit limit on float formatting in mode 0):

DECLARE @num3 TABLE (i decimal(9, 8))

INSERT  @num3
        SELECT  0.05
        UNION ALL
        SELECT  0.12345
        UNION ALL
        SELECT  3.14159265 
SELECT  i
       ,CASE WHEN PATINDEX('%[1-9]%', REVERSE(i)) < PATINDEX('%.%', REVERSE(i))
             THEN LEFT(i, LEN(i) - PATINDEX('%[1-9]%', REVERSE(i)) + 1)
             ELSE LEFT(i, LEN(i) - PATINDEX('%.%', REVERSE(i)))
        END 'Converted'
FROM    @num3
Cade Roux
This is complicated string manipulation.
Brad
@Brad - unfortunately, string manipulation is the way to do it if it *has* to be done in SQL - you could wrap the manipulation in a UDF. You could use SQL CLR instead, but wouldn't really want to go there myself. Downvotes a bit harsh IMHO - especially as they don't compromise the data returned.
AdaTheDev
@AdaTheDev - I would avoid a scalar UDF because they tend to perform poorly.
Cade Roux
@Brad - I agree there should be an easier syntax, but the operations it carries out are, effectively just what it has to do in order to yield the result (PATINDEX, REVERSE and LEN are all deterministic so each will only be evaluated once). The only thing possibly more efficient would probably be a CLR function which formats the decimal directly, digit by digit. I would benchmark it, though, especially if you are running this through thousands of rows.
Cade Roux