Trim decimal off a varchar value - sql

I've got a legacy SQL Server stored procedure that stopped working some time ago. While looking at it today, there is an inner join where one table is storing the value as an int and the other is storing it as a varchar in a (##.#) format. Not sure why or how that happened but SQL Server is none too happy about it.
I need a simple programmatic bit of string manipulation to pull out everything to the left of the decimal point so I can cast or convert it to an int to fix the join.
I started with the following, however substring requires a fixed length and the data could be 1-3 digits to the left of the decimal. Having trouble with the dynamic aspect of it. For clarity sake, I don't care what's to the right of the decimal.
cast(substring(H.Variable, 1, 1) as int)

First, find the index of the decimal by using CHARINDEX(). Then, you can pass that index to the LEFT() function:
LEFT(H.Variable, CHARINDEX('.', H.Variable) - 1)

Try:
CAST(TRY_CAST H.Variable AS Float) AS Int)
That should get you the integer value of the varchar string--if it cannot be converted, it will come back as NULL.
It's going in the other direction than your question, but is likely to be more accurate and higher performance.
Note that you need SQL Server 2012 or later to use the TRY_CAST conversion...

If you can have no decimals with decimals, you need to account for that.
declare #table table (c1 varchar(64))
insert into #table
values
('123')
,('5465465.465465')
select
case when CHARINDEX('.', c1) = 0 then c1 else LEFT(c1, CHARINDEX('.', c1) - 1) end
from #table
Other wise, only using LEFT() and CHARINDEX() will result in:
Invalid length parameter passed to the LEFT or SUBSTRING function.
Another way is
substring(c1,0,case when charindex('.',c1) = 0 then 9999 else charindex('.',c1) end)

Try:
CONVERT(INT, H)
It could be more tolerant...

Related

How to find values with certain number of decimal places using SQL?

I'm trying to figure out a way, using SQL, to query for values that go out to, say, 5 or more decimal places. In other words, I want to see only results that have 5+ decimal places (e.g. 45.324754) - the numbers before the decimal are irrelevant, however, I still need to see the full number. Is this possible? Any help if appreciated.
Assuming your DBMS supports FLOOR and your datatype conversion model supports this multiplication, you can do this:
SELECT *
FROM Table
WHERE FLOOR(Num*100000)!=Num*100000
This has the advantage of not requiring a conversion to a string datatype.
On SQL Server, you can specify:
SELECT *
FROM Table
WHERE Value <> ROUND(Value,4,1);
For an ANSI method, you can use:
SELECT *
FROM Table
WHERE Value <> CAST(Value*100000.0 AS INT) / 100000.0;
Although this method might cause an overflow if you're working with large numbers.
I imagine most DBMSs have a round function
SELECT *
FROM YourTable
WHERE YourCol <> ROUND(YourCol,4)
This worked for me in SQL Server:
SELECT *
FROM YourTable
WHERE YourValue LIKE '%._____%';
select val
from tablename
where length(substr(val,instr(val, '.')+1)) > 5
This is a way to do it in oracle using substr and instr
You can use below decode statement to identify maximum decimal present in database table
SELECT max(decode(INSTR(val,'.'), 0, 0, LENGTH(SUBSTR(val,INSTR(val,'.')+1)))) max_decimal
FROM tablename A;

SQL Server Extract INTs from VARCHAR

I know this looks like a duplicate, but I don't see the answer I'm looking for yet.
I have an ID column that is VARCHAR(36) for ID tokens. In a legacy system, these tokens are only INT. Now they are all mixed up, and I need to be able to extract only the integer tokens for certain operations, and they have to be converted to INTs.
I thought I could do that by this:
select top 100000 convert(int,CustomerToken) as CustomerToken
from Customer
WHERE (CustomerToken NOT LIKE '%[^-+ 0-9]%' AND CustomerToken < '214783647')
But there are some numeric values that I don't want. But some numeric values give problems. I get the error varchar value '11122241333' overflowed an int column.
This seems really odd to me. This seems even weirder:
SELECT 1 WHERE '11122241333' < '2147483647'
1
????
Has anyone seen this before? Anyone know what I can do about it?
You may try to "LPAD" your strings (I choose 20 as max length, which is of course arbitrary), if you want a "pseudo-number" comparison.
select top 10000 convert(int, CustomerToken) as CustomerToken
from Customer
WHERE (CustomerToken NOT LIKE '%[^-+ 0-9]%'
AND replicate('0', 20- len(CustomerToken)) + CustomerToken < '0000000000214783647')
If you have SQL Server 2012 or later then you can use try_parse().
SELECT TOP 100000 try_parse( CustomerToken as int ) AS CustomerToken
If the value cannot be cast then the function will return a null marker, otherwise it will return an int.

Good way to format decimal in SQL Server

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.
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
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
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.

SQL Server CONVERT(NUMERIC(18,0), '') fails but CONVERT(INT, '') succeeds?

PRINT CONVERT(NUMERIC(18,0), '')
produces Error converting data type varchar to numeric.
However,
PRINT CONVERT(INT, '')
produces 0 without error...
Question: Is there some SQL Server flag for this or will I need to do case statements for every varchar to numeric conversion? (aside from the obvious why?)
Use ISNUMERIC
declare #a varchar(20)
set #a = 'notanumber'
select case when isnumeric(#a) = 0 then 0 else convert(numeric(18,0),#a) end
ISNUMERIC doesn't alway work as you might expect: in particular it returns True for some values that can't subsequently be converted to numeric.
This article describes the issue and suggests how to work around it with UDFs.
Empty string will convert to zero for float and int types, but not decimal. (And converts to 01 Jan 1900 for datetimes = zero). I don't know why.. it just is...
If you need decimal(18,0), use bigint instead. Or cast via float first
ISNUMERIC will accept - and . and 1.2E3 as a number, but all fail to convert to decimal.

Converting a String to HEX in SQL

I'm looking for a way to transform a genuine string into it's hexadecimal value in SQL. I'm looking something that is Informix-friendly but I would obviously prefer something database-neutral
Here is the select I am using now:
SELECT SomeStringColumn from SomeTable
Here is the select I would like to use:
SELECT hex( SomeStringColumn ) from SomeTable
Unfortunately nothing is that simple... Informix gives me that message:
Character to numeric conversion error
Any idea?
Can you use Cast and the fn_varbintohexstr?
SELECT master.dbo.fn_varbintohexstr(CAST(SomeStringColumn AS varbinary))
FROM SomeTable
I'm not sure if you have that function in your database system, it is in MS-SQL.
I just tried it in my SQL server MMC on one of my tables:
SELECT master.dbo.fn_varbintohexstr(CAST(Addr1 AS VARBINARY)) AS Expr1
FROM Customer
This worked as expected. possibly what I know as master.dbo.fn_varbintohexstr on MS-SQL, might be similar to informix hex() function, so possibly try:
SELECT hex(CAST(Addr1 AS VARBINARY)) AS Expr1
FROM Customer
The following works in Sql 2005.
select convert(varbinary, SomeStringColumn) from SomeTable
Try this:
select convert(varbinary, '0xa3c0', 1)
The hex number needs to have an even number of digits. To get around that, try:
select convert(varbinary, '0x' + RIGHT('00000000' + REPLACE('0xa3c','0x',''), 8), 1)
If it is possible for you to do this in the database client in code it might be easier.
Otherwise the error probably means that the built in hex function can't work with your values as you expect. I would double check the input value is trimmed and in the format first, it might be that simple. Then I would consult the database documentation that describes the hex function and see what its expected input would be and compare that to some of your values and find out what the difference is and how to change your values to match that of the expected input.
A simple google search for "informix hex function" brought up the first result page with the sentence: "Must be a literal integer or some other expression that returns an integer". If your data type is a string, first convert the string to an integer. It looks like at first glance you do something with the cast function (I am not sure about this).
select hex(cast SomeStringColumn as int)) from SomeTable
what about:
declare #hexstring varchar(max);
set #hexstring = 'E0F0C0';
select cast('' as xml).value('xs:hexBinary( substring(sql:variable("#hexstring"), sql:column("t.pos")) )', 'varbinary(max)')
from (select case substring(#hexstring, 1, 2) when '0x' then 3 else 0 end) as t(pos)
I saw this here:
http://blogs.msdn.com/b/sqltips/archive/2008/07/02/converting-from-hex-string-to-varbinary-and-vice-versa.aspx
Sorrry, that work only on >MS SQL 2005
OLD Post but in my case I also had to remove the 0x part of the hex so I used the below code. (I'm using MS SQL)
convert(varchar, convert(Varbinary(MAX), YOURSTRING),2)
SUBSTRING(CONVERT(varbinary,Addr1 ) ,1,1) as Expr1