SQL - Changing data type of an alphanumeric column - sql

I'm on Teradata. I have an ID column that looks like this:
23
34
W7
007
021
90
GS8
I want to convert the numbers to numeric so the 007 should be 7 and 021 be 21. When a number is stored as a string, I usually do column * 1 to convert to numeric but in this case it gives me a bad character error since there are letters in there.
How would I do this in a select statement within a query?

Assuming that numeric values always start with a number, then something like this should work:
update t
set col = (case when substr(col, 1, 1) between '0' and '9'
then cast(cast(col as int) as varchar(255))
else col
end);
Or, you can forget the conversion and do:
update t
set col = trim(leading '0' from col);
Note: both of these assume that if the first character is a digit then the whole string comprises digits. The second assumes that the values are not all zeroes (or, more specifically, that returns the empty string).

Simply use TO_NUMBER(col) which returns NULL when the cast fails.

Related

Error converting varchar value to data type int

I am trying to concatenate two integer values with hyphen in between. So when I try to do the same, SQL gives me the error.
Conversion failed when converting the varchar value '30-45' to data type int.
NOTE:
Also, the second value for concatenation can be null so in that case, a hyphen should not be concatenated.
example
from1 = 30
to1 = 45
case
to1 is null
then from1
else CONCAT(from1, '-' + nullif(to1,'')) end
AS age
//This works but shows 3045 instead of 30-45.
concat(from, '-', to) AS age
//This doesn't work out as it gives the error 'Conversion failed when converting the varchar value '30-45' to data type int.'
Thanks for the help in advance and looking forward to it.
DECLARE #FROM INT=30;
DECLARE #TO INT=45;
SELECT CAST(#FROM AS VARCHAR(2))+'-'+CAST(ISNULL(#TO,'') AS VARCHAR(2));
SQL is trying to convert your phrase to int probably because it's part of CASE statement. It uses the first route to determine the output type.
In your case- you put NULL as the first route option in your CASE, so it is determined as int. try putting instead of it this: CAST(NULL AS VARCHAR(10))
It seems that for some reason you think that strings that contain mathematical expressions are resolved as said expression, not an as literal string. Thus if you have the varchar value '30-45' you think it'll return the int value -15; this isn't true. This in fact isn't true in any language, let alone T-SQL.
For what you have, in your ELSE the '-' isn't a minus... It's a string... - is a minus. If you want to substract a number from another then it's a basic maths expression: a - b. You're effectively doing CONVERT(varchar,a) + '-' + CONVERT(varchar,b)... Just have your ELSE as the following:
from1 - NULLIF(to1,0)
This will return NULL if from1 has the value NULL, or to1 has the value NULL or 0.
Please check below code. It's working
example
#from1 = 30
#to1 = 45
IF #to1 is null
SELECT #from1
ELSE
SELECT CONCAT(#from1, '-' , nullif(#to1,'')) as age

Concatenate and add a character to integer columns in SQL

I have a 10 Character length values in a column in SQL Server. I need to split that column at fixed length and remove the leading zeros and add a - after each of the values.
I am able to split the values by using Substring and converting them to int. It is working well.
However, when I try to concatenate it is failing. Appreciate if you can help.
SELECT TOP 1 R.COL1, CAST(SUBSTRING(R.COL1,1,1) AS int) AS F1,CAST(SUBSTRING(R.COL1,2,5) AS int) AS F2,CAST(SUBSTRING(R.COL1,7,4) AS int) AS F3 CAST(SUBSTRING(R.COL1,1,1) AS int) +'-' +CAST(SUBSTRING(R.COL1,2,5) AS int) +'-' + CAST(SUBSTRING(R.COL1,7,4) AS int) AS finalString FROM MYTABLE R
If the value for COL1 IS 1012950001 the finalString I am expecting is 1-1295-1
however the result I am getting from the above query is 1297 as it is adding all the values.
Appreciate if you can help.
You can't use the + operator with a numerical data type and a varchar that cannot implicitly be converted to that data type. Something like 1 + 'a' isn't going to work, as 'a' isn't an int, and can't be implicitly converted to one.
If you are mixing data types, then use CONCAT, which implicitly converts each part into a (n)varchar:
CONCAT({Numerical Expression},'a',{Other varchar Expression})
You can use concat method to concatenate the substring value
select
concat(CAST(SUBSTRING('1012950001',1,1) AS int), '-',
CAST(SUBSTRING('1012950001',2,5) AS int), '-',
CAST(SUBSTRING('1012950001',7,4) AS int)) AS finalString
This will give you the expected result '1-1295-1'

Datatype trouble in SQL Server 2008

I have a data something like this.
70.6
70.60
70.7
70.70
I can't use varchar as I need to perform arithmetic operations (>,< or floor), when I used float all records change to 70.7 and 70.6 from 70.70 and 70.60
When I changed to decimal(2,2), then all 70.6 records changed to 70.60.
Please suggest which data type suits for me.
Business need to retain 70.6 as it is and 70.60 as it is.
Currently data is in dataware house and stored in varchar.
I am preparing data mart and written query like
Result1 = CASE WHEN Dia = '' OR Dia > 28 OR M.Dia < 6 THEN 'Dia' END,
Result2 = CASE WHEN Width = '' OR Width > 16 OR M.Width < 3 THEN 'Width' END,
Result6 = CASE WHEN Bore] = '' OR FLOOR(LOG10(REVERSE(ABS(M.[Center Bore])+1)))+1 <> 2 THEN 'Bore' END,
From the mathematical point of view, there is no difference between 70.6 and 70.60. If your business rules must treat these values as different values, and you want to also be able to perform mathematical operations of them, you should keep them as decimal in your database, and I suggest adding a tinyint column that will specify the number of decimal digits of the original string value.
create a stored procedure that will get the value as string, calculate the number of decimal digits, convert the string to decimal, and save both of these values into the database.
When selecting the value you convert it to string and manipulate the decimal digits as you please.
You can use Convert(float, **) to convert the data from nvarchar.
I don't think there would be any difference can occur when your data is either 60.6 or 60.60 while performing arithmetic operation (>,< or floor)
select convert(float, '60.6') as val
Output: 60.6
as you mentioned in the comment
because I am checking data have only 1 digit after decimal
Then you can form get such a string using charindex and left.
select left(val, charindex('.', val) + 1) as new_val
from (select '60.6666' as val) as x
Input string : 60.6666
Output String : 60.6
now you can use
convert(float, new_val) as val
like,
select convert(float, left(val, charindex('.', val) + 1)) as val
from (select '60.6666' as val) as x

Remove leading zeros

Given data in a column which look like this:
00001 00
00026 00
I need to use SQL to remove anything after the space and all leading zeros from the values so that the final output will be:
1
26
How can I best do this?
Btw I'm using DB2
This was tested on DB2 for Linux/Unix/Windows and z/OS.
You can use the LOCATE() function in DB2 to find the character position of the first space in a string, and then send that to SUBSTR() as the end location (minus one) to get only the first number of the string. Casting to INT will get rid of the leading zeros, but if you need it in string form, you can CAST again to CHAR.
SELECT CAST(SUBSTR(col, 1, LOCATE(' ', col) - 1) AS INT)
FROM tab
In DB2 (Express-C 9.7.5) you can use the SQL standard TRIM() function:
db2 => CREATE TABLE tbl (vc VARCHAR(64))
DB20000I The SQL command completed successfully.
db2 => INSERT INTO tbl (vc) VALUES ('00001 00'), ('00026 00')
DB20000I The SQL command completed successfully.
db2 => SELECT TRIM(TRIM('0' FROM vc)) AS trimmed FROM tbl
TRIMMED
----------------------------------------------------------------
1
26
2 record(s) selected.
The inner TRIM() removes leading and trailing zero characters, while the outer trim removes spaces.
This worked for me on the AS400 DB2.
The "L" stands for Leading.
You can also use "T" for Trailing.
I am assuming the field type is currently VARCHAR, do you need to store things other than INTs?
If the field type was INT, they would be removed automatically.
Alternatively, to select the values:
SELECT (CAST(CAST Col1 AS int) AS varchar) AS Col1
I found this thread for some reason and find it odd that no one actually answered the question. It seems that the goal is to return a left adjusted field:
SELECT
TRIM(L '0' FROM SUBSTR(trim(col) || ' ',1,LOCATE(' ',trim(col) || ' ') - 1))
FROM tab
One option is implicit casting: SELECT SUBSTR(column, 1, 5) + 0 AS column_as_number ...
That assumes that the structure is nnnnn nn, ie exactly 5 characters, a space and two more characters.
Explicit casting, ie SUBSTR(column,1,5)::INT is also a possibility, but exact syntax depends on the RDBMS in question.
Use the following to achieve this when the space location is variable, or even when it's fixed and you want to make a more robust query (in case it moves later):
SELECT CAST(SUBSTR(LTRIM('00123 45'), 1, CASE WHEN LOCATE(' ', LTRIM('00123 45')) <= 1 THEN LEN('00123 45') ELSE LOCATE(' ', LTRIM('00123 45')) - 1 END) AS BIGINT)
If you know the column will always contain a blank space after the start:
SELECT CAST(LOCATE(LTRIM('00123 45'), 1, LOCATE(' ', LTRIM('00123 45')) - 1) AS BIGINT)
both of these result in:
123
so your query would
SELECT CAST(SUBSTR(LTRIM(myCol1), 1, CASE WHEN LOCATE(' ', LTRIM(myCol1)) <= 1 THEN LEN(myCol1) ELSE LOCATE(' ', LTRIM(myCol1)) - 1 END) AS BIGINT)
FROM myTable1
This removes any content after the first space character (ignoring leading spaces), and then converts the remainder to a 64bit integer which will then remove all leading zeroes.
If you want to keep all the numbers and just remove the leading zeroes and any spaces you can use:
SELECT CAST(REPLACE('00123 45', ' ', '') AS BIGINT)
While my answer might seem quite verbose compared to simply SELECT CAST(SUBSTR(myCol1, 1, 5) AS BIGINT) FROM myTable1 but it allows for the space character to not always be there, situations where the myCol1 value is not of the form nnnnn nn if the string is nn nn then the convert to int will fail.
Remember to be careful if you use the TRIM function to remove the leading zeroes, and actually in all situations you will need to test your code with data like 00120 00 and see if it returns 12 instead of the correct value of 120.

how do i filter out non-numeric values in a text field in teradata?

oI have a teradata table with about 10 million records in it, that stores a numeric id field as a varchar. i need to transfer the values in this field to a bigint column in another table, but i can't simply say cast(id_field as bigint) because i get an invalid character error. looking through the values, i find that there could be a character at any position in the string, so let's say the string is varchar(18) i could filter out invalid rows like so :
where substr(id_field,1,1) not in (/*big,ugly array of non-numeric chars*/)
and substr(id_field,2,1) not in (/*big,ugly array of non-numeric chars*/)
etc, etc...
then the cast would work, but this is not feasible in the long run. it's slow and if the string has 18 possible characters, it makes the query unreadable. how can i filter out rows that have a value in this field that will not cast as a bigint without checking each character individually for an array of non-numeric characters?
example values would be
123abc464
a2.3v65
a_356087
........
000000000
BOB KNIGHT
1235468099
the values follow no specific patterns, I simply need to filter out the ones that contain ANY non-numeric data.
123456789 is okay but 123.abc_c3865 is not...
Starting with TD14 Teradata added some functions, now there are multiple ways, e.g.:
WHERE RTRIM(col, '0123456789') = ''
But the easiest way is TO_NUMBER, which returns NULL for bad data:
TO_NUMBER(col)
The best that I've ever managed is this:
where char2hexint(upper(id_field)) = char2hexint(lower(id_field))
Since upper case characters give a different hex value to lower case ones, this will ensure that you have no alphabetical characters, but will still leave you with underscores, colons and so forth. If this doesn't meet your requirements, you may need to write an UDF.
could we also try to divide the values in the field by some integer "if divided then must be a number and if not and throws some error,then must have some character...." guess this would be lot fast as has just mathematics involved...
I've faced the same issue to try to exclude alpha characters from street address house numbers. The following will work if you don't mind concatanating all the numeric numbers together......
It checks if the upper of a string equals the lower of the string, if so it's a number, if not it becomes null.
select cast(case when upper(substring('12E'from 1 for 1)) = lower(substring('12E'from 1 for 1)) then substring('12E'from 1 for 1) else null end ||
case when upper(substring('12E'from 2 for 1)) = lower(substring('12E'from 2 for 1)) then substring('12E'from 2 for 1) else null end ||
case when upper(substring('12E'from 3 for 1)) = lower(substring('12E'from 3 for 1)) then substring('12E'from 3 for 1) else null end ||
case when upper(substring('12E'from 4 for 1)) = lower(substring('12E'from 4 for 1)) then substring('12E'from 4 for 1) else null end ||
case when upper(substring('12E'from 5 for 1)) = lower(substring('12E'from 5 for 1)) then substring('12E'from 5 for 1) else null end ||
case when upper(substring('12E'from 2 for 1)) = lower(substring('12E'from 2 for 1)) then substring('12E'from 2 for 1) else null end
as integer)
Try using this code segment
WHERE id_Field NOT LIKE '%[^0-9]%'
I found lins314159 answer to be very helpful with a similar issue. It may be an old thread but for what it's worth, I used:
char2hexint(upper(id_field)) = char2hexint(lower(id_field)) AND substr(id_field,1,1) IN ('1' to '9')
to successfully cast the remaining VARCHAR results to INT
SELECT customer_id
FROM t
WHERE UPPER(customer_id)(CASESPECIFIC) <>
LOWER(customer_id)(CASESPECIFIC);
This works perfectly fine to check whether the values in a numeric field is non-numeric.
SELECT id_field
WHERE oTranslate(id_field, '0123456789','')<>'';
This works well for me! It reveals any id_field containing a non-numeric value