Data Conversion error in SQL, unsure what field it could be referring to - select

Msg 8114, Level 16, State 5, Line 1 Error converting data type varchar to numeric.
Below is the code that I am using and the schema for the fields mentioned in the code. Some context behind this, I have a set list of indcodes. I only give one below but there are 350 in total. It is quite likely when i query by indcode, area, and ownership that the data does not exist. Hence, why I have the isnull language. Finally, I need rows that contains a value of suppress = 1 to show up as N/A.
For every indcode that I query, I need a result. The result could be actual data or some text (NULL, N/A, etc).
Last is the intended result. I only gave code for one indcode but have included six to give the example some depth.
select
CASE
WHEN suppress = 0 then isnull (mnth1emp, 0)
ELSE 'N/A'
END as mnth1emp,
CASE
WHEN suppress = 0 THEN isnull (mnth2emp, 0)
ELSE 'N/A'
END as mnth2emp,
CASE
WHEN suppress = 0 THEN isnull (mnth3emp, 0)
ELSE 'N/A'
END as mnth3emp
from dbo.industryimport20172f
where area='000003' and indcode='21' and ownership='00'
suppress char (1)
mnth1emp numeric(9,0)
mnth2emp numeric(9,0)
mnth3emp numeric(9,0)
area char(6)
indcode char (6)
ownership char(2)
123 456 789
1 2 3
Null null null
2 3 4
3 4 5
Null Null Null

So the first things that jump out here are:
a) While you're asking for numbers to be returned in the case statement, you're then asking for a string when you get to ELSE. Try casting all the fields as varchars and then entering them as strings:
CASE
WHEN cast(suppress as varchar) = '0' then isnull (cast(mnth1emp as varchar), '0')
ELSE 'N/A'
END as mnth1e
You may not need to cast suppress.
b) Does supress ever have anything other than a number in it? If so, you would need to put the zero as a string:
CASE WHEN supress = '0' --etc.

Related

Cast to int instead of decimal?

I have field that has up to 9 comma separated values each of which have a string value and a numeric value separated by colon. After parsing them all some of the values between 0 and 1 are being set to an integer rather than a numeric as cast. The problem is obviously related to data type but I am unsure what is causing it or how to fix it. The problem only exists in the case statement, the split_part function seems to be working perfect.
Things I have tried:
nvl(split_part(one,':',2),0) = COALESCE types text and integer cannot be matched
nvl(split_part(one,':',2)::numeric,0) => Invalid input syntax for type numeric
numerous other cast/convert variations
(CASE WHEN split_part(one,':',2) = '' THEN 0::numeric ELSE split_part(one,':',2)::numeric END)::numeric => runs but get int value of 0
When using the split_part function outside of case statement it does work correctly. However, I need the result to be zero for null values.
split_part(one,':',2) => 0.02068278096187390979 (expected result)
When running the code above I get zero but expect 0.02068278096187390979
Field "one" has the following value 'xyz: 0.02068278096187390979' before the split_part function.
EXAMPLE:
create table test(one varchar);
insert into test values('XYZ: 0.50000000000000000000')
select
one ,split_part(one,':',2) as correct_value_for_those_that_are_not_null ,
case
when split_part(one,':',2) = '' then null
else split_part(one,':',2)::numeric
end::numeric as this_one_is_the_problem
from test
However, I need the result to be zero for null values.
Your example does not deal with NULL values at all, though. Only addressing the empty string ('').
To replace either with 0 reliably, efficiently and without casting issues:
SELECT part1, CASE WHEN part2 <> '' THEN part2::numeric ELSE numeric '0' END AS part2
FROM (
SELECT split_part(one, ':', 1) AS part1
, split_part(one, ':', 2) AS part2
FROM test
) sub;
See:
Best way to check for "empty or null value"
Also note that all SQL CASE branches must agree on a common data type. There have been minor adjustments in the logic that determines the resulting type in the past, so the version of Postgres may play a role in corner cases. Don't recall the details now.
nvl()is not a Postgres function. You probably meant COALESCE. The manual:
This SQL-standard function provides capabilities similar to NVL and IFNULL, which are used in some other database systems.

Update with ISNULL and operation

original query looks like this :
UPDATE reponse_question_finale t1, reponse_question_finale t2 SET
t1.nb_question_repondu = (9-(ISNULL(t1.valeur_question_4)+ISNULL(t1.valeur_question_6)+ISNULL(t1.valeur_question_7)+ISNULL(t1.valeur_question_9))) WHERE t1.APPLICATION = t2.APPLICATION;
I know you cannot update 2 tables in a single query so i tried this :
UPDATE reponse_question_finale t1
SET nb_question_repondu = (9-(COALESCE(t1.valeur_question_4,'')::int+COALESCE(t1.valeur_question_6,'')::int+COALESCE(t1.valeur_question_7)::int+COALESCE(t1.valeur_question_9,'')::int))
WHERE t1.APPLICATION = t1.APPLICATION;
But this query gaves me an error : invalid input syntax for integer: ""
I saw that the Postgres equivalent to MySQL is COALESCE() so i think i'm on the good way here.
I also know you cannot add varchar to varchar so i tried to cast it to integer to do that. I'm not sure if i casted it correctly with parenthesis at the good place and regarding to error maybe i cannot cast to int with coalesce.
Last thing, i can certainly do a co-related sub-select to update my two tables but i'm a little lost at this point.
The output must be an integer matching the number of questions answered to a backup survey.
Any thoughts?
Thanks.
coalesce() returns the first non-null value from the list supplied. So, if the column value is null the expression COALESCE(t1.valeur_question_4,'') returns an empty string and that's why you get the error.
But it seems you want something completely different: you want check if the column is null (or empty) and then subtract a value if it is to count the number of non-null columns.
To return 1 if a value is not null or 0 if it isn't you can use:
(nullif(valeur_question_4, '') is null)::int
nullif returns null if the first value equals the second. The IS NULL condition returns a boolean (something that MySQL doesn't have) and that can be cast to an integer (where false will be cast to 0 and true to 1)
So the whole expression should be:
nb_question_repondu = 9 - (
(nullif(t1.valeur_question_4,'') is null)::int
+ (nullif(t1.valeur_question_6,'') is null)::int
+ (nullif(t1.valeur_question_7,'') is null)::int
+ (nullif(t1.valeur_question_9,'') is null)::int
)
Another option is to unpivot the columns and do a select on them in a sub-select:
update reponse_question_finale
set nb_question_repondu = (select count(*)
from (
values
(valeur_question_4),
(valeur_question_6),
(valeur_question_7),
(valeur_question_9)
) as t(q)
where nullif(trim(q),'') is not null);
Adding more columns to be considered is quite easy then, as you just need to add a single line to the values() clause

Crystal Reports If true then return number else return NULL

In Crystal Reports, is it possible to have a function that returns a numeric value if the if statement evaluates to true and returns NULL otherwise?
I currently have
IF ({INDICATOR} = 'Y') Then
(
{numeric value}
)
Else
(
0
);
But since 0 is a possible value of {numeric value} it doesn't make sense. Rather, I would rather have that field come up blank if the indicator isn't 'Y', but when I replace the 0 with NULL it gives me a type mismatch error.
Is there a way for me to only show the value when the indicator is 'Y'?
If you truly want a null value and not empty try the following
create a formula called NULL then save it and close without entering any data in the formula area. Then in your formula above try
If {INDICATOR} = 'Y' then {numeric value}
else tonumber({#NULL})
you can't return two different datatypes in a single if statement..If if is number then else should also be number.. instead try to split the statements and try.. something like below.
IF ({INDICATOR} = 'Y') Then
(
ToText({numeric value})
)
Else if ({INDICATOR} <> 'Y') Then
(
""
);
If {INDICATOR} = 'Y' then {numeric value}
else {Command.NULLCOL}
The setup in Database Expert is to use Add Command with sql:
select null as nullcol
from dual
Then left join to it.
A returned null value can be very powerful, so your need for a null value should not be questioned. Null values automatically display differently to stand out. Compared to 0 or "", null values work correctly with DistinctCount function. Null values also work correctly with section summaries and crosstabs, which can save you a lot of work which is the whole point of using crystal.

Filtering stored procedure records by nested select case statement

I need to further refine my stored proc resultset from this post, I need to filter my resultset to display only records where emailaddr is NULL (meaning display only records that have Invoice_DeliveryType value of 'N' ).
Among numerous queries, I have tried:
select
Invoice_ID, 'Unknown' as Invoice_Status,
case when Invoice_Printed is null then '' else 'Y' end as Invoice_Printed,
case when Invoice_DeliveryDate is null then '' else 'Y' end as Invoice_Delivered,
(case when Invoice_DeliveryType <> 'USPS' then ''
when exists (Select 1
from dbo.Client c
Where c.Client_ID = SUBSTRING(i.Invoice_ID, 1, 6) and
c.emailaddr is not null
)
then 'Y'
else 'N'
end)
Invoice_ContactLName + ', ' + Invoice_ContactFName as ContactName,
from
dbo.Invoice
left outer join
dbo.fnInvoiceCurrentStatus() on Invoice_ID = CUST_InvoiceID
where
CUST_StatusID = 7
AND Invoice_ID = dbo.Client.Client_ID
AND dbo.client.emailaddr is NULL
order by
Inv_Created
but I get an error
The conversion of the nvarchar value '20111028995999' overflowed an int column
How can I get the stored procedure to only return records with DeliveryType = 'N' ?
Trying selecting the stored proc results into a temp table, then select
* from #TempTable
We could really do with a schema definition to get this problem resolved.
It appears that there is an implicit conversion occurring within one of your case statements, but without the schema def's it's difficult to track down which one.
You can't safely mix datatypes in CASE expressions, unless you are absolutely sure that any implicit conversions will work out OK you should make the conversions explicit.
Judging by the error message seeming to include something that could be a date represented as a string(20111028) plus some kind of other data ?time?(995999) it may be something to do with Invoice_DeliveryDate, but this is a shot in the dark without more details.

How can I query 'between' numeric data on a not numeric field?

I've got a query that I've just found in the database that is failing causing a report to fall over. The basic gist of the query:
Select *
From table
Where IsNull(myField, '') <> ''
And IsNumeric(myField) = 1
And Convert(int, myField) Between #StartRange And #EndRange
Now, myField doesn't contain numeric data in all the rows [it is of nvarchar type]... but this query was obviously designed such that it only cares about rows where the data in this field is numeric.
The problem with this is that T-SQL (near as I understand) doesn't shortcircuit the Where clause thus causing it to ditch out on records where the data is not numeric with the exception:
Msg 245, Level 16, State 1, Line 1
Conversion failed when converting the nvarchar value '/A' to data type int.
Short of dumping all the rows where myField is numeric into a temporary table and then querying that for rows where the field is in the specified range, what can I do that is optimal?
My first parse purely to attempt to analyse the returned data and see what was going on was:
Select *
From (
Select *
From table
Where IsNull(myField, '') <> ''
And IsNumeric(myField) = 1
) t0
Where Convert(int, myField) Between #StartRange And #EndRange
But I get the same error I did for the first query which I'm not sure I understand as I'm not converting any data that shouldn't be numeric at this point. The subquery should only have returned rows where myField contains numeric data.
Maybe I need my morning tea, but does this make sense to anyone? Another set of eyes would help.
Thanks in advance
IsNumeric only tells you that the string can be converted to one of the numeric types in SQL Server. It may be able to convert it to money, or to a float, but may not be able to convert it to an int.
Change your
IsNumeric(myField) = 1
to be:
not myField like '%[^0-9]%' and LEN(myField) < 9
(that is, you want myField to contain only digits, and fit in an int)
Edit examples:
select ISNUMERIC('.'),ISNUMERIC('£'),ISNUMERIC('1d9')
result:
----------- ----------- -----------
1 1 1
(1 row(s) affected)
You'd have to force SQL to evaluate the expressions in a certain order.
Here is one solution
Select *
From ( TOP 2000000000
Select *
From table
Where IsNumeric(myField) = 1
And IsNull(myField, '') <> ''
ORDER BY Key
) t0
Where Convert(int, myField) Between #StartRange And #EndRange
and another
Select *
From table
Where
CASE
WHEN IsNumeric(myField) = 1 And IsNull(myField, '') <> ''
THEN Convert(int, myField) ELSE #StartRange-1
END Between #StartRange And #EndRange
The first technique is "intermediate materialisation": it forces a sort on a working table.
The 2nd relies on CASE ORDER evaluation is guaranteed
Neither is pretty or whizzy
SQL is declarative: you tell the optimiser what you want, not how to do it. The tricks above force things to be done in a certain order.
Not sure if this helps you, but I did read somewhere that incorrect conversion using CONVERT will always generate error in SQL. So I think it would be better to use CASE in where clause to avoid having CONVERT to run on all rows
Use a CASE statement.
declare #StartRange int
declare #EndRange int
set #StartRange = 1
set #EndRange = 3
select *
from TestData
WHERE Case WHEN ISNUMERIC(Value) = 0 THEN 0
WHEN Value IS NULL THEN 0
WHEN Value = '' THEN 0
WHEN CONVERT(int, Value) BETWEEN #StartRange AND #EndRange THEN 1
END = 1