SQL Server : remove "decimals" from nvarchar - sql

I have some data that has come in as a nvarchar. Clearly the data was originally converted from a numeric based datatype. For example I have values that are 17.0000000. I would like to remove these trailing zeros so that it is just "17". I do need the output in either varchar or nvarchar.

You can get rid of the decimal and zeros afterwards using:
select (case when col like '%.0%' and col not like '%.%[^0]%'
then left(col, charindex('.', col) - 1)
when col like '%.%0'
then replace(rtrim(replace(col, '0', ' ')), ' ', '0')
else col
end)
Note: This assumes that the value is strictly numeric (hence doesn't have its own spaces).
However, I would suggest that you convert the value to an appropriate numeric/decimal type.

Yet another option if 2012+
Example
Declare #YourTable Table ([StrValue] varchar(50))
Insert Into #YourTable Values
('17.00000')
,('17.10000')
,('.1')
,('.0')
,('Cat')
,('07/29/2017')
Select *
,NewVal = coalesce(convert(varchar(50),try_convert(float,StrValue)),StrValue)
From #YourTable
Returns
StrValue NewVal
17.00000 17
17.10000 17.1
.1 0.1
.0 0
Cat Cat
07/29/2017 07/29/2017

A double cast will also get rid of the trailing zeros
select cast(cast('17.0000000' as float) as varchar)
union
select cast(cast('17.1000000' as float) as varchar)
results in
17
17.1

SELECT LEFT('17.0000000',CHARINDEX('17.0000000','.')-1)
I've hardcoded the value here but you would replace that with your column name

Another way with out using case can be:
select col
, reverse( -- use reverse to find from right
substring(
reverse(col),
patindex( -- finding first char that is not `0`
'%[^0]%',
reverse(col)) +
patindex( -- finding first char that is not `.` after removing trailing `0`s
'%[^.]%',
substring( -- remove trailing `0`s
reverse(col),
patindex('%[^0]%', reverse(col)),
len(col)) + 'x') - 1, -- Note: I add `'x'` to avoid error
len(col)))
from t;
SQL Server Fiddle Demo

Related

Remove white spaces from string in sql

SELECT CONVERT(DECIMAL(18,2)
,ROUND( REPLACE
(
REPLACE(
SUBSTRING([ColumnName],0, CHARINDEX(' ',[ColumnName],1) )
,'$',''
)
,',',''
)
,2
)
) AS 'ColumnName'
,[ColumnName]
,*
FROM TABLENAME
The CHARINDEX returns index of space, but when there is no space in data it returns 0. What I want is when ever there is a white space at the end data, SUBSTRING should consider that and when there is no white space then it should consider the length of the string.
It seems to you are working with SQL Server, then i would like to apply case expression
case when CHARINDEX(' ',[ColumnName],1) > 0
then CHARINDEX(' ',[ColumnName],1)
else len([ColumnName]) end
Apparently you're working with sql-server and want to convert a string like $123,456,789.99 to a DECIMAL.
TRY_PARSE should get you the result you want:
SELECT
TRY_PARSE(REPLACE('$123,456,789.99 ', '$', '')
AS DECIMAL(18,2)
USING 'en-US') AS myDecimalNumber
Or if it's an option for you to work with the MONEY data-type you can omit the REPLACE:
SELECT
TRY_PARSE('$123,456,789.99 '
AS MONEY
USING 'en-US')) AS myDecimalNumber

Convert VarChar to Float with different culture format

From different external sources I get data where some numbers are in a NVarChar field. Until now I used a REPLACE with a CAST to ensure that numbers with a "," where cast the right way. Like this:
select cast(replace('12,5',',','.') as float)
select cast(replace('12.5',',','.') as float)
This has worked just fine, but now I get data where there is also a thousand separator in. Like this:
select cast(replace('2.012,5',',','.') as float)
select cast(replace('2,012.5',',','.') as float)
It' broken.
Is there a way to detect which data format is used in a NVarChar with a number?
I have tried to use TRY_PARSE with a culture parameter, it works well if there is a thousand separator but not without:
SELECT #Fuelunits =
CASE
WHEN ISNUMERIC(TRY_PARSE(#Hoeveelheid AS decimal(9,2) USING 'nl-NL')) = 1
THEN CAST(TRY_PARSE(#Hoeveelheid AS decimal(9,2) USING 'nl-NL') AS FLOAT)
ELSE CAST(TRY_PARSE(#Hoeveelheid AS decimal(9,2) USING 'en-US') AS FLOAT)
END
The problem is that I have to use this in an UPDATE and that that the data format can differ in the same table.
Any suggestions?
You can use CHARINDEX() to work out what separators are present and where they are in the string along with a CASE expression to handle different cases before you REPLACE and CAST to FLOAT:
CREATE TABLE #vals (val NVARCHAR(10));
INSERT INTO #vals
(
val
)
VALUES
(N'2.012,5'),
(N'2,012.5');
SELECT CAST(CASE
-- is there a '.' in a position before a ','?
WHEN CHARINDEX('.', val) < CHARINDEX(',', val) THEN
-- yes - remove the '.' and replace the ',' with '.'
REPLACE(REPLACE(val, '.', ''), ',', '.')
ELSE
-- no - just remove the ','
REPLACE(v.val, ',', '')
END AS FLOAT)
FROM #vals AS v;
DROP TABLE #vals;
References:
CHARINDEX (Transact-SQL)
Searches an expression for another expression and returns its starting position if found.

How to sort a varchar column that contains numbers and letters in SQL Server?

I have a varchar column that contain numbers (1-99999) and letters (AM0001-BF9999).
Since it has letters so i can't just convert it to int.
Is there a way to maybe use grouping_id to sort this column by numbers (small to large) then follow by letters (alphabetically)?
Thanks..
You need to know what the maximum length of your field is. Assuming 25 characters for illustrative purposes, this will work:
select
v
from (
select
right(space(25) + v,25) as v
from ( values
('1-99999')
,('AM0001-BF9999')
) data(v)
)data
order by v
to yield:
v
-------------------------
1-99999
AM0001-BF9999
You can try using the ISNUMERIC function like this:
select * from test_table
order by
case isnumeric(test_column)
when 1 then convert(int,test_column)
else 999999 end, test_column
Sql fiddle demo.
That's what you get when you denormalize your database schema.
Prefix and number should be stored separately.
That said, this is what I did when I had the same problem:
SELECT * FROM YOUR_TABLE
ORDER BY dbo.GetNumbers(YOUR_FIELD), YOUR_FIELD
Create Function dbo.GetNumbers(#Data VarChar(8000))
Returns int
AS
Begin
Return CAST(Left(
SubString(#Data, PatIndex('%[0-9.-]%', #Data), 8000),
PatIndex('%[^0-9.-]%', SubString(#Data, PatIndex('%[0-9.-]%', #Data), 8000) + 'X')-1) AS int)
End
See also this post for extracting numbers from strings
http://blogs.lessthandot.com/index.php/DataMgmt/DataDesign/extracting-numbers-with-sql-server/

Varchar to Numeric conversion - CLR or 'e0'

I want to convert data from Varchar column to Numeric data type -
so before conversion I am calling ISNUMERIC function to check whether data is numeric and if yes convert it to numeric data type. But I am facing an issue -
IsNumeric function is not behaving as expected -
- IsNumeric(x) returns true - when varchar value has both comma and a tab character (Char(9)),
- IsNumeric(x) returns false - when varchar value has only tab character and no comma
It is explained with the help of below SQL -
DECLARE #propValue AS VARCHAR(50)
SET #propValue = '1,592 ' -- contains comma + tab (Char(9))
SELECT ISNUMERIC(#propValue) -- Returns 1
--If ISNUMERIC func returns true for this value, lets convert this Varchar value to Numeric
SELECT CAST(#propValue AS Numeric(19, 4)) -- :-( Error converting data type varchar to numeric.
I Googled and found various solutions to tackle this problem -
--Solution 1: use 'e0'
SELECT ISNUMERIC(#propValue + 'e0') -- Returns 0
--Solution 2: remove comma before calling IsNumeric()
SELECT ISNUMERIC(REPLACE(#propValue, ',', '')) -- Returns 0
--Solution 3
--Call CLR function to parse Varchar value
What is the recommended solution in above scenario and why?
Also, I would really appreciate if anyone can explain why IsNumeric(x) returns false - when varchar value has only tab character and no comma?
Thank you!
Keep in mind that ISNUMERIC() = 1 does not mean "can be converted to every numeric type" but rather "can be converted to at least one numeric type." This comes up a lot where the value can be converted to at least one numeric type, but not the one you want. A much more basic example:
IF ISNUMERIC(256) = 1
SELECT CONVERT(TINYINT, 256);
If you have strings that have known violations (such as tabs), then why not also replace tabs? Why not prevent garbage data from getting into this value in the first place?
This works but it is quite ugly:
DECLARE #x TABLE (propValue VARCHAR(50));
INSERT #x SELECT '1,592' + CHAR(9)
UNION ALL SELECT '55' + CHAR(9) + '32'
UNION ALL SELECT CHAR(9) + '7,452.32 '
UNION ALL SELECT 'foo'
UNION ALL SELECT '74';
SELECT CONVERT(NUMERIC(19,4),
LTRIM(RTRIM(REPLACE(REPLACE(propValue, CHAR(9), ''), ',', '')))
)
FROM #x
WHERE ISNUMERIC(LTRIM(RTRIM(REPLACE(REPLACE(propValue,
CHAR(9), ''), ',', ''))) + 'e0') = 1;
While not applicable to your exact question, I wrote a FAQ about this 10 years ago: http://classicasp.aspfaq.com/general/what-is-wrong-with-isnumeric.html
ISNUMERIC(RTRIM(LTRIM(x))) = 1

cast or convert a float to nvarchar?

I need to select from one column of datatype float and insert it in another column as nvarchar.
I tried to cast it: cast([Column_Name] as nvarchar(50))
The result was 9.07235e+009 instead of a 10 digit number (phone number).
Does any one know how to cast or convert this data properly?
Check STR. You need something like SELECT STR([Column_Name],10,0) ** This is SQL Server solution, for other servers check their docs.
If you're storing phone numbers in a float typed column (which is a bad idea) then they are presumably all integers and could be cast to int before casting to nvarchar.
So instead of:
select cast(cast(1234567890 as float) as nvarchar(50))
1.23457e+009
You would use:
select cast(cast(cast(1234567890 as float) as int) as nvarchar(50))
1234567890
In these examples the innermost cast(1234567890 as float) is used in place of selecting a value from the appropriate column.
I really recommend that you not store phone numbers in floats though!
What if the phone number starts with a zero?
select cast(0100884555 as float)
100884555
Whoops! We just stored an incorrect phone number...
Do not use floats to store fixed-point, accuracy-required data.
This example shows how to convert a float to NVARCHAR(50) properly, while also showing why it is a bad idea to use floats for precision data.
create table #f ([Column_Name] float)
insert #f select 9072351234
insert #f select 907235123400000000000
select
cast([Column_Name] as nvarchar(50)),
--cast([Column_Name] as int), Arithmetic overflow
--cast([Column_Name] as bigint), Arithmetic overflow
CAST(LTRIM(STR([Column_Name],50)) AS NVARCHAR(50))
from #f
Output
9.07235e+009 9072351234
9.07235e+020 907235123400000010000
You may notice that the 2nd output ends with '10000' even though the data we tried to store in the table ends with '00000'. It is because float datatype has a fixed number of significant figures supported, which doesn't extend that far.
For anyone willing to try a different method, they can use this:
select FORMAT([Column_Name], '') from YourTable
This will easily change any float value to nvarchar.
Float won't convert into NVARCHAR directly, first we need to convert float into money datatype and then convert into NVARCHAR, see the examples below.
Example1
SELECT CAST(CAST(1234567890.1234 AS FLOAT) AS NVARCHAR(100))
output
1.23457e+009
Example2
SELECT CAST(CAST(CAST(1234567890.1234 AS FLOAT) AS MONEY) AS NVARCHAR(100))
output
1234567890.12
In Example2 value is converted into float to NVARCHAR
You can also do something:
SELECT CAST(CAST(34512367.392 AS decimal(30,9)) AS NVARCHAR(100))
Output:
34512367.392000000
I had same problem and i saw your solution.
Good solution, its worked, thank you...
I created a function with your codes. Now i use it.
My function is here:
create function dbo.fnc_BigNumbertoNvarchar (#MyFloat float)
returns NVARCHAR(50)
AS
BEGIN
RETURN REPLACE (RTRIM (REPLACE (REPLACE (RTRIM ((REPLACE (CAST (CAST (#MyFloat AS DECIMAL (38 ,18 )) AS VARCHAR( max)), '0' , ' '))), ' ' , '0'), '.', ' ')), ' ','.')
END
Continuing a1ex07's answer - to use STR function (SQL SERVER),
and Ronen Festinger's comment - that he gets asterisks instead of digits,
I wanted to point out that the default length of STR is 10,
therefore, for large numbers, don't forget to use the length argument
For example: STR(1234567890123, 14)
DECLARE #MyFloat [float]
SET #MyFloat = 1000109360.050
SELECT REPLACE (RTRIM (REPLACE (REPLACE (RTRIM ((REPLACE (CAST (CAST (#MyFloat AS DECIMAL (38 ,18 )) AS VARCHAR( max)), '0' , ' '))), ' ' , '0'), '.', ' ')), ' ','.')