111

I have a column DECIMAL(9,6) i.e. it supports values like 999,123456.

But when I insert data like 123,4567 it becomes 123,456700

How to remove those zeros?

Espo
  • 41,399
  • 21
  • 132
  • 159
abatishchev
  • 98,240
  • 88
  • 296
  • 433

23 Answers23

180

A decimal(9,6) stores 6 digits on the right side of the comma. Whether to display trailing zeroes or not is a formatting decision, usually implemented on the client side.

But since SSMS formats float without trailing zeros, you can remove trailing zeroes by casting the decimal to a float:

select 
    cast(123.4567 as DECIMAL(9,6))
,   cast(cast(123.4567 as DECIMAL(9,6)) as float)

prints:

123.456700  123,4567

(My decimal separator is a comma, yet SSMS formats decimal with a dot. Apparently a known issue.)

Andomar
  • 232,371
  • 49
  • 380
  • 404
  • 9
    +1 I thought the conversion to float would introduce some imprecision to the results but it appears to work absolutely fine. – Martin Smith May 30 '10 at 11:21
  • 1
    One downside to this method is if you start with "2.0" it will turn it into "2". This is probably OK for the person asking the question, but I needed to be able to keep a single zero after the decimal, without keeping any other trailing zeros. @user1959416's answer solves that. – Mason G. Zhwiti Jan 11 '13 at 18:50
  • 8
    Plus float in general is a very poor choice for storing numbers. You will get rounding errors as it is not an exact type. Never use float. – HLGEM Aug 07 '13 at 18:53
  • 1
    The comment about floats being formatted without trailing zeros was extremely useful – Sanjiv Jivan Mar 27 '16 at 00:17
  • Am I correct in thinking though that the scale and precision of a decimal can exceed that of a float and hence there may be cases where (with a significant of more than 17 digits) this answer doesn't work out? – Caius Jard May 16 '18 at 05:38
39

I was reluctant to cast to float because of the potential for more digits to be in my decimal than float can represent

FORMAT when used with a standard .net format string 'g8' returned the scientific notation in cases of very small decimals (eg 1e-08) which was also unsuitable

Using a custom format string (https://learn.microsoft.com/en-us/dotnet/standard/base-types/custom-numeric-format-strings) allowed me to achieve what I wanted:

DECLARE @n DECIMAL(9,6) =1.23;
SELECT @n
--> 1.230000
SELECT FORMAT(@n, '0.######')
--> 1.23

If you want your number to have at least one trailing zero, so 2.0 does not become 2, use a format string like 0.0#####

The decimal point is localized, so cultures that use a comma as decimal separator will encounter a comma output where the . is

Of course, this is the discouragable practice of having the data layer doing formatting (but in my case there is no other layer; the user is literally running a stored procedure and putting the result in an email :/ )

Caius Jard
  • 72,509
  • 5
  • 49
  • 80
  • 2
    Yes, this is the only solution that allows full control over numbers to the right of the decimal separator, while avoiding scientific notation. The only problem with this solution is that FORMAT is really (!) slow. (Still.. on SQL2019) – Tor Nov 30 '20 at 19:25
  • This is the correct answer. You don't want to convert data types but simply format the existing data. – The.Laughing.Man Aug 17 '23 at 14:06
36

You can use the FORMAT() function (SqlAzure and Sql Server 2012+):

SELECT FORMAT(CAST(15.12     AS DECIMAL(9,6)), 'g18')  -- '15.12'
SELECT FORMAT(CAST(0.0001575 AS DECIMAL(9,6)), 'g10')  -- '0.000158'
SELECT FORMAT(CAST(2.0       AS DECIMAL(9,6)), 'g15')  -- '2'

Be careful when using with FLOAT (or REAL): don't use g17 or larger (or g8 or larger with REAL), because the limited precision of the machine representation causes unwanted effects:

SELECT FORMAT(CAST(15.12 AS FLOAT), 'g17')         -- '15.119999999999999'
SELECT FORMAT(CAST(0.9 AS REAL), 'g8')             -- '0.89999998'
SELECT FORMAT(CAST(0.9 AS REAL), 'g7')             -- '0.9'

Furthermore, note that, according to the documentation:

FORMAT relies on the presence of the .NET Framework Common Language Runtime (CLR). This function will not be remoted since it depends on the presence of the CLR. Remoting a function that requires the CLR would cause an error on the remote server.

Works in SqlAzure, too.

robert4
  • 1,072
  • 15
  • 20
  • 1
    For my purposes, I found a format string of g8 formatted my number as "1e-08" which wasn't what I was after. This answer did lead me to one I could use though – Caius Jard May 16 '18 at 05:39
20
SELECT CONVERT(DOUBLE PRECISION, [ColumnName])
Bat_Programmer
  • 6,717
  • 10
  • 56
  • 67
  • SQL Server 2008 and above – Bat_Programmer Jun 23 '15 at 02:02
  • 1
    what happens when the number is like "123.10705000000"? I tried with SELECT CONVERT(DOUBLE PRECISION,123.10705000000) but it gives me "123.107" as answer. and I want "123.10705" as output? Is there any way? I don't want to use CHARINDEX. – Bhavika Zimbar Oct 06 '16 at 10:05
8
SELECT REVERSE(ROUND(REVERSE(2.5500),1))

prints:

2.55
Jonathan Dursi
  • 50,107
  • 9
  • 127
  • 158
user1959416
  • 113
  • 1
  • 1
  • 2
    This method is nice in that it will leave a trailing zero on if there is only a zero. So 2.5500 returns 2.55, and 2.000 returns 2.0 rather than 2. Great for when you're formatting engine sizes in a vehicle... – Mason G. Zhwiti Jan 11 '13 at 18:46
  • 4
    @MasonG.Zhwiti I have doubt this will work with some decimal with more digits after the decimal point like 232.33220003200 for example :- ) – gotqn May 31 '13 at 14:48
  • @gotqn Good point, that definitely fails. However, for our specific use case (formatting engine sizes in cars), it works perfectly. :) – Mason G. Zhwiti May 31 '13 at 16:03
  • as @gotqn said.. it's buggy when the number is long – Ofir Hadad Aug 21 '13 at 14:14
  • 1
    This doesn't exactly work for numbers like 0.56000 . it will yield 56. Funny – Gunjan Shakya Jan 24 '18 at 22:21
  • Doesnt work for some numbers like REVERSE(ROUND(REVERSE(799908651.0000000),1)) and returns 2.0 – Rakesh Oct 12 '21 at 09:42
6

Try this :

SELECT REPLACE(TRIM(REPLACE(20.5500, "0", " ")), " ", "0")

Gives 20.55

Denim Datta
  • 3,740
  • 3
  • 27
  • 53
Todd
  • 877
  • 8
  • 5
  • 2
    REPLACE(TRIM(REPLACE(20.00, "0", " ")), " ", "0") leaves you with a trailing . => "20." – Keith Sirmons Jan 08 '14 at 20:44
  • It is perfectly applicable to my case and seems to be the simpliest solution. Thumb & vote up! – Oak_3260548 Jul 30 '19 at 14:54
  • Great solution without having to convert to float! one minor issue spotted `0.000` became `.`. here is the fix `SELECT REPLACE(RTRIM(REPLACE(20.5500, "0", " ")), " ", "0")` to trim trailing zeros only – wilson Sep 23 '20 at 04:47
  • 1
    this is to get rid of the dot : `SELECT REPLACE(RTRIM(REPLACE(REPLACE(RTRIM(REPLACE(25.00, '0', ' ')), ' ', '0'),'.',' ')),' ','.')` – Mohamed Ashraf Oct 26 '21 at 11:39
5
Cast(20.5500 as Decimal(6,2))

should do it.

abatishchev
  • 98,240
  • 88
  • 296
  • 433
Peter Jones
  • 85
  • 1
  • 1
2

I had a similar issue, but was also required to remove the decimal point where no decimal was present, here was my solution which splits the decimal into its components, and bases the number of characters it takes from the decimal point string on the length of the fraction component (without using CASE). To make matters even more interesting, my number was stored as a float without its decimals.

DECLARE @MyNum FLOAT
SET @MyNum = 700000
SELECT CAST(PARSENAME(CONVERT(NUMERIC(15,2),@MyNum/10000),2) AS VARCHAR(10)) 
+ SUBSTRING('.',1,LEN(REPLACE(RTRIM(REPLACE(CAST(PARSENAME(CONVERT(NUMERIC(15,2),@MyNum/10000),1) AS VARCHAR(2)),'0',' ')),' ','0'))) 
+ REPLACE(RTRIM(REPLACE(CAST(PARSENAME(CONVERT(NUMERIC(15,2),@MyNum/10000),1) AS VARCHAR(2)),'0',' ')),' ','0') 

The result is painful, I know, but I got there, with much help from the answers above.

Adge Cutler
  • 34
  • 1
  • 5
2

The best way is NOT converting to FLOAT or MONEY before converting because of chance of loss of precision. So the secure ways can be something like this :

CREATE FUNCTION [dbo].[fn_ConvertToString]
(
    @value sql_variant
)
RETURNS varchar(max)
AS
BEGIN
    declare @x varchar(max)
    set @x= reverse(replace(ltrim(reverse(replace(convert(varchar(max) , @value),'0',' '))),' ',0))

    --remove "unneeded "dot" if any
    set @x = Replace(RTRIM(Replace(@x,'.',' ')),' ' ,'.')
    return @x
END

where @value can be any decimal(x,y)

Mahmoud Moravej
  • 8,705
  • 6
  • 46
  • 65
  • @abatishchev , fn_ is a preferred prefix for sql functions , prefixes is used in standard coding and naming convention as well as best practices , we can customize our prefixes , but for best practices we use `sp_` for stored procedure , `fn_` for functions , `tbl` for tables and so on... this is not a requirement but this is best practices to organize our databases. – japzdivino Jan 26 '16 at 08:13
  • 1
    @japongskie: sorry, but no. There is no need for prefixes, at all. This is actually the worst practice. See https://msdn.microsoft.com/en-us/library/dd172115(v=vs.100).aspx http://sqlperformance.com/2012/10/t-sql-queries/sp_prefix http://dba.stackexchange.com/q/25348/3186 and many more – abatishchev Jan 26 '16 at 08:19
  • @abatishchev , oh i see.. so i will not follow the teaching of school anymore .. haha LOL , since your link came from mdsn , thanks for this one, i will change now my best practice .. :) – japzdivino Jan 26 '16 at 08:31
2

I had a similar problem, needed to trim trailing zeros from numbers like xx0000,x00000,xxx000

I used:

select LEFT(code,LEN(code)+1 - PATINDEX('%[1-Z]%',REVERSE(code))) from Tablename

Code is the name of the field with the number to be trimmed. Hope this helps someone else.

Martin Tournoij
  • 26,737
  • 24
  • 105
  • 146
  • This comment works well when you are using a version of SQL Server that is old enough that you can't user the TRIM or FORMAT build in functions in SQL Server. – David Parvin Mar 26 '19 at 21:04
  • I did find one issue with this answer. If the value in the 'code' field is something like '10' then it will return '1'. If the number is '10.00', I think it ignores the decimal point too. – David Parvin Mar 27 '19 at 14:57
1

Another option...

I don't know how efficient this is but it seems to work and does not go via float:

select replace(rtrim(replace(
       replace(rtrim(replace(cast(@value as varchar(40)), '0', ' ')), ' ', '0')
       , '.', ' ')), ' ', '.')

The middle line strips off trailing spaces, the outer two remove the point if there are no decimal digits

SQLian
  • 21
  • 2
1

I needed to remove trailing zeros on my decimals so I could output a string of a certain length with only leading zeros

(e.g. I needed to output 14 characters so that 142.023400 would become 000000142.0234),

I used parsename, reverse and cast as int to remove the trailing zeros:

SELECT
    PARSENAME(2.5500,2)
    + '.'
    + REVERSE(CAST(REVERSE(PARSENAME(2.5500,1)) as int))

(To then get my leading zeros I could replicate the correct number of zeros based on the length of the above and concatenate this to the front of the above)

I hope this helps somebody.

Ali
  • 109
  • 7
  • @Protiguous Since there is 1 decimal point, 2.5500 is read like .. The second parameter of 2 returns schema name, the second parameter of 1 returns the object name. It would usually be used like PARSENAME('dbo.TableName', 2) to return dbo or PARSENAME('dbo.TableName', 1) to return TableName. – Ali Jun 12 '20 at 15:27
  • Hello.. I see my alias is flagged in your comment. I do not know why? – Protiguous Jun 20 '20 at 17:56
  • The exact question you asked me on May 26th 2020 was “How is PARSENAME supposed to work here???” Sorry it took so long to reply to you. – Ali Jun 21 '20 at 18:34
1

it is possible to remove leading and trailing zeros in TSQL

  1. Convert it to string using STR TSQL function if not string, Then

  2. Remove both leading & trailing zeros

    SELECT REPLACE(RTRIM(LTRIM(REPLACE(AccNo,'0',' '))),' ','0') AccNo FROM @BankAccount
    
  3. More info on forum.

abatishchev
  • 98,240
  • 88
  • 296
  • 433
Ishtiaq
  • 27
  • 2
  • 4
    A bit ugly but this version kills the leftover '.': `REPLACE(RTRIM(REPLACE(REPLACE(RTRIM(REPLACE(X,'0',' ')),' ','0'),'.',' ')),' ','.')` – Chris B Jul 01 '14 at 18:58
  • 1
    Be carefull, if number is not decimal it will trim zeroes too. CHARINDEX('.',@Number) != 1 will test that. – Muflix Feb 28 '15 at 14:06
  • My previous decimal check is wrong. Here is better: Select Len(@Test) - Len(Replace(@Test, 'a', '')) As NumberOfCharacters Explained: http://tinyurl.com/o4fc8g7 and http://tinyurl.com/kgzkuqk – Muflix Feb 28 '15 at 14:26
1

The easiest way is to CAST the value as FLOAT and then to a string data type.

CAST(CAST(123.456000 AS FLOAT) AS VARCHAR(100))
0

How about this? Assuming data coming into your function as @thisData:

BEGIN
  DECLARE @thisText VARCHAR(255)
  SET @thisText = REPLACE(RTRIM(REPLACE(@thisData, '0', ' ')), ' ', '0')
  IF SUBSTRING(@thisText, LEN(@thisText), 1) = '.'
    RETURN STUFF(@thisText, LEN(@thisText), 1, '')
  RETURN @thisText
END
0
case when left(replace(ltrim(rtrim(replace(str(XXX, 38, 10), '0',  ' '))), ' ', '0'), 1) = '.'
then '0' 
else ''
end +

replace(ltrim(rtrim(replace(str(XXX, 38, 10), '0',  ' '))), ' ', '0') +

case when right(replace(ltrim(rtrim(replace(str(XXX, 38, 10), '0',  ' '))), ' ', '0'), 1) = '.'
then '0' 
else ''
end
beloblotskiy
  • 948
  • 9
  • 7
  • Wounldn't this also replace the 0's (zeros) in between the numbers? Dont' think replace just works at the ends... – mtk Feb 13 '14 at 13:23
0

I understand this is an old post but would like to provide SQL that i came up with

DECLARE @value DECIMAL(23,3)
set @value = 1.2000
select @value original_val, 
    SUBSTRING(  CAST( @value as VARCHAR(100)), 
                0,
                PATINDEX('%.%',CAST(@value as VARCHAR(100)))
            )
      + CASE WHEN ROUND( 
                        REVERSE( SUBSTRING( CAST(@value as VARCHAR(100)),
                                        PATINDEX('%.%',CAST(@value as VARCHAR(100)))+1,
                                        LEN(CAST(@value as VARCHAR(100)))
                                        )
                                )
                    ,1) > 0 THEN 
            '.' 
            +  REVERSE(ROUND(REVERSE(SUBSTRING( CAST(@value as VARCHAR(100)),
                                                PATINDEX('%.%',CAST(@value as VARCHAR(100)))+1,
                                                LEN(CAST(@value as VARCHAR(100)))
                                                )
                ),1))
        ELSE '' END  AS modified_val
Abhi
  • 824
  • 9
  • 8
0

I know this thread is very old but for those not using SQL Server 2012 or above or cannot use the FORMAT function for any reason then the following works.

Also, a lot of the solutions did not work if the number was less than 1 (e.g. 0.01230000).

Please note that the following does not work with negative numbers.

DECLARE @num decimal(28,14) = 10.012345000
SELECT PARSENAME(@num,2) + REPLACE(RTRIM(LTRIM(REPLACE(@num-PARSENAME(@num,2),'0',' '))),' ','0') 

set @num = 0.0123450000
SELECT PARSENAME(@num,2) + REPLACE(RTRIM(LTRIM(REPLACE(@num-PARSENAME(@num,2),'0',' '))),' ','0') 

Returns 10.012345 and 0.012345 respectively.

Alan Schofield
  • 19,839
  • 3
  • 22
  • 35
0

try this.

select CAST(123.456700 as float),cast(cast(123.4567 as DECIMAL(9,6)) as float)
Vishal Kiri
  • 1,248
  • 1
  • 12
  • 24
0

When I converted long deicmals to nvarchar, I used convertion to double precision and casting to nvarchar

SELECT CAST(CONVERT(DOUBLE PRECISION, 1.234567000000) as nvarchar(255))

Output:

1.23457
Alex Vazhev
  • 1,363
  • 1
  • 18
  • 17
-1

Try this:

select isnull(cast(floor(replace(rtrim(ltrim('999,999.0000')),',','')) as int),0)
abatishchev
  • 98,240
  • 88
  • 296
  • 433
kierzo
  • 113
  • 4
-1

A DECIMAL(9,6) column will convert to float without loss of precision, so CAST(... AS float) will do the trick.


@HLGEM: saying that float is a poor choice for storing numbers and "Never use float" is not correct - you just have to know your numbers, e.g. temperature measurements would go nicely as floats.

@abatishchev and @japongskie: prefixes in front of SQL stored procs and functions are still a good idea, if not required; the links you mentioned only instructs not to use the "sp_" prefix for stored procedures which you shouldn't use, other prefixes are fine e.g. "usp_" or "spBob_"

Reference: "All integers with 6 or fewer significant decimal digits can be converted to an IEEE 754 floating-point value without loss of precision": https://en.wikipedia.org/wiki/Single-precision_floating-point_format

Kobus
  • 19
  • 4
  • I used float once. it was a dogs breakfast. I will never use it again :) decimal(28,12) all the way baby. – hamish Aug 02 '22 at 13:08
-1

Try this:

select Cast( Cast( (ROUND( 35.457514 , 2) *100) as Int) as float ) /100
eeerahul
  • 1,629
  • 4
  • 27
  • 38
  • I prefer @user1959416's answer better here, as it doesn't change the values. For example, starting with 2.5550, your method results in 2.56, whereas theirs returns 2.555. – Mason G. Zhwiti Jan 11 '13 at 18:45