REPLACE to just have a number causing conversion failure - sql

I'm trying to do a count to see how many fields in column value are > 10:
SELECT
COUNT(CASE WHEN t.value > 10)
THEN 1
ELSE NULL
END
FROM table t
WHERE t.DATE = '2017-01-01'
However, the column has a few custom entries like +15 or >14.0, so I added the following:
SELECT
COUNT(CASE WHEN value LIKE '>%'
and Replace(value, '>', '') > 10)
FROM table t
WHERE t.DATE = '2017-01-01'
However, after doing that, I get the following error:
Conversion failed when converting the varchar value '>14.0' to data
type int. Warning: Null value is eliminated by an aggregate or other
SET operation.
Seeing I have no access to rewrite the database with an UPDATE, does anyone have a workaround solution?

You could fix this, either by simply changing 10 to 10.0:
SELECT CASE WHEN '14.0' > 10.0 THEN 1 ELSE 0 END
This will cause the implicit conversion of '14.0' to decimal rather than int, which works, or you explicitly convert it:
SELECT CASE WHEN CONVERT(DECIMAL(14, 2), '14.0') > 10 THEN 1 ELSE 0 END
If it were me however, and I was not in a position to update the data, and do something a bit left field, like use a numeric data type to store numbers, I would ignore these values completely, and simply use TRY_CONVERT to avoid the conversion errors:
SELECT
COUNT(CASE WHEN TRY_CONVERT(DECIMAL(14, 2), value) > 10 THEN 1 END)
It is a varchar column, so the possibilities of what nonsense could be in there are endless, you might get a query that works now by replacing > and +, but then what about when someone puts in <, or ends up with a space in between like + 14, or something completely random like 'aaaa', where does it end?

It would be helpful to see the table and sample data, but it sounds like you have strings that are numbers and a sign.
You can cast it to convert the data since you are mixing and matching data types.
SELECT
COUNT(CASE WHEN CAST(value AS VARCHAR(10)) LIKE '>%'
and CAST(Replace(value, '>', '') AS your_num_datatype_here) > 10)

Related

Using BETWEEN function

I have this query, using which I am trying to categorize my data. If the first character is between 0 and 9, I want to categorize it with the first character. If it is anything else including special characters or alphabets, then I want to use 10.
select CUSTOMER_ID, CASE
WHEN LEFT(CUSTOMER_ID, 1) BETWEEN 0 AND 9 THEN LEFT(CUSTOMER_ID, 1)
ELSE '10'
END
AS CUST_DIGIT
from CUSTOMER
I get this error when I run the above query:
Conversion failed when converting the nvarchar value 'A' to data type
int.
This is what my data looks like. Could you please help point what I could change.
Update your between values to string as '0' AND '9' then it will work.
Reason you are getting error is when you perform LEFT it will return string and you are comparing it with int as 0 AND 9 are int, So it will try to convert your result value from LEFT to int.
Your some of the record have digit at beginning of value those will work fine but when record comes like A46564 it won't be able to cast A to int and throw error.
SELECT CUSTOMER_ID, CASE
WHEN LEFT(CUSTOMER_ID, 1) BETWEEN '0' AND '9' THEN LEFT(CUSTOMER_ID, 1)
ELSE '10'
END AS CUST_DIGIT
FROM CUSTOMER
I would initially answer the same as #Karan.
Just for completeness... In your case, a possible alternative would be to use ISNUMERIC:
select
CUSTOMER_ID,
CASE
WHEN ISNUMERIC(LEFT(CUSTOMER_ID, 1)) = 1 THEN LEFT(CUSTOMER_ID, 1)
ELSE '10'
END AS CUST_DIGIT
from
CUSTOMER
And yet another approach would be to use the LIKE operator:
select
CUSTOMER_ID,
CASE
WHEN CUSTOMER_ID LIKE '[0-9]%' THEN LEFT(CUSTOMER_ID, 1)
ELSE '10'
END AS CUST_DIGIT
from
CUSTOMER

Matching two values of different types in two SQL databases

I am trying to compare records between two different SQL tables/databases in my Node project and have to do some transformation in order to compare the values.
In one database (MariaDB) the value is of type INT, and looks like this: 516542
In the other (SQL Server) database the value I need to match to is of type char(21), and looks like this: 00000516542-000
What I tried doing was this:
WHERE (REPLACE(LEFT( LM301.DOCNUMBR, CHARINDEX('-', LM301.DOCNUMBR)), '-', '')) = 516542
This works for some records, but for others I get this error:
"The conversion of the varchar value '0004000009123' overflowed an int
column."
If I pass the first value in as a string ('516542') it doesn't match at all.
How can I handle this scenario?
The error you're getting is at least correct. But from your example i can't determine whether the conversion is right or not.
Basically, somewhere in your CHAR(21). There a value which is greater than int32, or SQL Server int type, in value. This value is: 2,147,483,648. 4,000,009,123 is greater than this max value as specified by the error message.
The DBMS, with this where statement, will try to do the operation and compare to all records, and it runs into an overflow. You could do a string compare instead. Or try an explicit conversion and convert it to bigint.
WHERE CONVERT(BIGINT, (REPLACE(LEFT( LM301.DOCNUMBR, CHARINDEX('-', LM301.DOCNUMBR)), '-', ''))) = 516542
It's doing an implicit cast to INT because that's your compare type, then overflows. Making the conversion explicit allows you to determine the datatype instead.
Basically what's happening:
IF ('21474836480' >= 100) --Implicit conversion: Error and prints false
PRINT 'True'
ELSE
PRINT 'False'
IF ('214748364' >= 100) --Implicit Conversion: True
PRINT 'True'
ELSE
PRINT 'False'
IF (CONVERT(BIGINT, '21474836480') >= 100) --Explicit Conversion: Prints True
PRINT 'True'
ELSE
PRINT 'False'
So wrapping your value in an explicit conversion should resolve your error.
You need to do explicit type conversation with TRY_CONVERT():
TRY_CONVERT(BIGINT, LEFT(LM301.DOCNUMBR, CHARINDEX('-', LM301.DOCNUMBR + '-') - 1)) = 516542
TRY_CONVERT() will return NULL if conversation fail.
You don't need to use replace(), you can subtract the position.
EDIT : Try_CONVERT() is available from 2012 +. For older version you can do :
(CONVERT(BIGINT, LEFT(LM301.DOCNUMBR, CHARINDEX('-', LM301.DOCNUMBR) - 1)) = 516542 AND
CHARINDEX('-', LM301.DOCNUMBR) > 0)
)
Note : This might fail if DOCNUMBR doesn't have numeric value prior to -.

SQL Server - How to check if string is text or any representation of 0?

I have a 'non-clean' column Col1 of type nvarchar(20) containing numbers (both integers and decimals) and various representations of the text 'No Data'
(e.g no-data, no data, NO DATA, etc) for cases where the value cannot be found.
Am looking for a query which will fetch me only records that contain ANY representation of 0 (like 0, 00, 0.00 etc) or the exact text 'NO-DATA'.
I am unable to find ways to use regular expression in SQL Server 2016.
This should be pretty simple:
select (case when try_convert(float, col) = 0 then 1 else 0 end) as IsZero
try_convert() returns NULL if the conversion doesn't work.
In general, comparison of floating point numbers to constants isn't recommended. In this case, I'm pretty sure all reasonable representations of zero would be exact.
If that is a concern, you could do:
select (case when try_convert(int, replace(col, '.', '')) = 0 then 1 else 0 end) as IsZero
Of course, this would allow 0.0.0.

SQL string '00000' displaying as '0'

Can someone explain why
CASE
WHEN MARK = 'Y'
THEN LEFT('00000', 5-LEN(DATEDIFF(MINUTE, START, FINISH))) + DATEDIFF(MINUTE, START, FINISH)
ELSE '00000'
END AS [Time]
Is displaying as a single 0 instead of 00000 when Mark <> 'Y', and displaying 35 instead of 00035 (as an example)
I would guess SQL is converting it to an integer.
Code like this select cast('00000' as varchar) returns as you wish (00000, 00035) but select cast('00000' as int) returns your results (0, 35 etc)
My understanding is that you are using MSSQL server. If, yes then the default datatype for any variable or nullable column is INT

sql - conversion error when changing 'and' to 'or'

I have a database table in sql server 2008. My query is breaking for a reason that is unknown to me:
select release_id, url_id,tt_projectid, release_title, tech_area, current_state, dateadd(ss,last_built,'12/31/1969 20:00:00') as recent_Date,
autobuild_count, manualbuild_count, bcm_build_count, config_count, force_count, transition_only_count,
auto_integ_count,last_auto_integ,dateadd(ss,integ_complete_date,'12/31/1969 20:00:00') as integ_date
from tablename
where (auto_integ_count > 0
and MONTH(last_auto_integ) = '1'
and YEAR(last_auto_integ) = '2013')
and (release_id > 36000)
order by release_id desc
The above query works fine, but when I change the last line of the where close from 'and' to 'or' I get this conversion error:
Conversion failed when converting date and/or time from character string.
I'm puzzled as to why changing
'and (release_id > 36000)'
to
'or (release_id > 36000)'
would cause such an error
The reason is because last_auto_integ is being stored as a string rather than as a date. These lines in the where clause are not being executed with the and -- by happenstance -- because none occur when release_id > 360000.
From what I can see, there are no other places in the query where you might be converting a string to a date format.
You can identify these values using:
select last_auto_integ
from tablename
where isdate(last_auto_integ) = 0 and last_auto_integ is not null
You can fix the problem in the query by using case:
where month(case when isdate(last_auto_integ) = 1 then last_auto_integ end) = 1 and
year(case when isdate(last_auto_integ) = 1 then last_auto_integ end) = 2013
Or, you can just use substring() to extract the month and year from whatever date format you are using.
Because when you change AND to OR you are getting a lot more rows returned, and one of these other expressions is failing:
dateadd(ss,integ_complete_date,'12/31/1969 20:00:00')
MONTH(last_auto_integ)
YEAR(last_auto_integ)
With only AND, it doesn't need to evaluate the other expressions for rows whose release_id is <= 36000, so it's not encountering the strings that are causing the problem on date conversion.