Conversion failed when converting the varchar value in case statement - sql-server

I cant not get my head around it. We have following simple query.
DECLARE #bFlag bit
SET #bFlag = 0
SELECT something = CASE
WHEN #bFlag = 1 THEN
CASE
WHEN RS.intInterval = 1 THEN '"Days"'
WHEN RS.intInterval = 2 THEN '"Weeks"'
WHEN RS.intInterval = 3 THEN '"Months"'
WHEN RS.intInterval = 4 THEN '"Years"'
END
Else
RS.intInterval
End
from MyTable AS RS WITH (NOLOCK)
So I want to get intInterval(which is int) if flag is not set to true. Otherwise if flag is set to true, I want to get Days, Weeks, etc depending upon value of intInterval. If I run this with #bFalg = 1, I get this error:
Conversion failed when converting the varchar value '"Weeks"' to data
type int
which does not make any sense as I am not converting anything.
I know I can fix it by putting cast (intInterval as varchar) in else part. However I want to know the reason why I am getting this error, why case is trying to convert 'Weeks' to int?

When using CASE statement, all result expressions must have the same data type. If not, the result will be converted to the data type with a higher precedence. According to BOL:
Returns the highest precedence type from the set of types in
result_expressions and the optional else_result_expression.
Since INT has a higher data type precedence than VARCHAR, "Weeks" get converted to INT and that produces the error:
Conversion failed when converting the varchar value '"Weeks"' to data
type int
Another example that will produce the same error:
SELECT CASE WHEN 1 = 1 THEN 'True' ELSE 0 END
The solution is to convert RS.intInterval to VARCHAR:
CONVERT(VARCHAR(10), RS.intInterval)
Your final query should be:
DECLARE #bFlag bit
SET #bFlag = 0
SELECT something = CASE
WHEN #bFlag = 1 THEN
CASE
WHEN RS.intInterval = 1 THEN '"Days"'
WHEN RS.intInterval = 2 THEN '"Weeks"'
WHEN RS.intInterval = 3 THEN '"Months"'
WHEN RS.intInterval = 4 THEN '"Years"'
END
Else
CONVERT(VARCHAR(10), RS.intInterval)
End
from MyTable AS RS WITH (NOLOCK)

Related

Condition check in where clause based on parameter passed to stored procedure

The stored procedure I am working on has 2 parameters #IsApproved (BIT) and CustomId (INT).
Now in my WHERE clause I want to check if #IsApproved or not, if it is approved then use A.[FunctionalId] = #CustomId else A.[InstallId] = #CustomId.
I tried like this, but it throws an error.
SELECT
AppKeyId, AppName, AppVersion
FROM
dbo.[Application] A
WHERE
CASE
WHEN #IsApproved = 1 THEN A.[FunctionalId] = #CustomId
ELSE A.[InstallId] = #CustomId
END
A CASE expression returns a scalar value, not a boolean result; THEN A.[FunctionalId] = #CustomId isn't valid as it's not a scalar value.
Use an OR:
SELECT AppKeyId,
AppName,
AppVersion
FROM dbo.Application A
WHERE (#IsApproved = 1 AND A.[FunctionalId] = #CustomId)
OR (#IsApproved = 0 AND A.[InstallId] = #CustomId);

Conversion failed when converting the varchar value to data type int in sql query

I'm trying a dynamic SQL query but I'm getting an error about conversion but can't figure out what the problem is.
Here's my query :
DECLARE #VarSubCriBusqueda VARCHAR(MAX)
SET #VarSubCriBusqueda = 'Marca'
DECLARE #InputString VARCHAR(MAX)
SET #InputString = '%'
SELECT
Marcas.MarcaID, Marcas.Marca, Clases.ClaseNo, Marcas.Codigo, Propietarios.Propietario
FROM
Marcas
LEFT OUTER JOIN
Propietarios ON marcas.PropietarioID = Propietarios.PropietarioID
LEFT OUTER JOIN
Clases ON Marcas.ClaseIntID = clases.ClaseID
LEFT OUTER JOIN
Clientes ON Clientes.ClienteID = Marcas.ClienteID
WHERE
CASE #VarSubCriBusqueda
WHEN 'Clases.ClaseNo'
THEN Clases.ClaseNo
WHEN 'Codigo'
THEN Codigo
WHEN 'Propietarios.Propietario'
THEN Propietarios.Propietario
WHEN 'Clientes.Empresa'
THEN Clientes.Empresa
WHEN 'Contacto'
THEN Marcas.Contacto
WHEN 'Marca'
THEN Marca
END LIKE #InputString
It end with the following message:
Msg 245, Level 16, State 1, Line 6
Conversion failed when converting the varchar value 'ACADEMY AWARDS' to data type int.
Any help?
In all likelihood. you are missing the fact that a case expression returns a single type. And, if any of the then or else clauses are numbers, then all are converted to numbers. I imagine that one or more of the columns are numbers. One fix is explicit conversion.
A better fix is to get rid of the case expression entirely:
WHERE (#VarSubCriBusqueda = 'Clases.ClaseNo' AND Clases.ClaseNo like #InputString) OR
(#VarSubCriBusqueda = 'Codigo' AND Codigo like #InputString) OR
. . .
And even with this formulation, you should use the correct comparison for your type. So, if you have a number, LIKE doesn't seem appropriate.

Why is my CASE statement requiring the THEN part to be of data type INT?

I am trying to run a query where the below CASE statement is one of the lines. I'm using Report Builder 3.0.
However, I get an error that says :
Conversion failed when converting the varchar value 'Case 1' to data type int; Microsoft SQL Server, Error: 245".
Why is the CASE statement requiring the THEN part to be an INT data type ?
(CASE
WHEN jobs.Uf_Production_Line = 'LN BM6'
THEN 'Case 1'
ELSE
99999
END
) AS line
When using CASE statement, all result expressions must have the same data type. If not, the result will be converted to the data type with a higher precedence. According to BOL
Returns the highest precedence type from the set of types in
result_expressions and the optional else_result_expression.
And since INT has a higher data type precedence than VARCHAR, your query produces an error:
Conversion failed when converting the varchar value 'Case 1' to data
type int; Microsoft SQL Server, Error: 245".
To fix this, you should convert your ELSE part to VARCHAR.
ELSE '99999'
Because your else uses a value with data type int:
ELSE 99999
You use data types (varchar and int) that can't be exchanged automatically.
An option is to use:
ELSE '99999'
You should use '99999' instead of 99999. All values should be the same datatype in CASE, for now in your ELSE part values is of INT datatype.
Full code should be like:
(CASE WHEN jobs.Uf_Production_Line = 'LN BM6' THEN 'Case 1'
ELSE '99999'
END
) AS line
A case statement can only return one data type. So use the number as varchar:
(CASE WHEN jobs.Uf_Production_Line = 'LN BM6'
THEN 'Case 1'
ELSE '99999'
END
) AS line
OR you can return NULL instead of 9999 if you want to represent it as an invalid value for Line:
(CASE WHEN jobs.Uf_Production_Line = 'LN BM6'
THEN 'Case 1'
ELSE NULL
END
) AS line
Because 99999 is an int. Both cases must return the same data type.

How to get all values including null in a SQL Server case statement?

I have a big stored procedure, and basically I want to select all values (including null) if my variable #DimBrowserId is set to 0. I am using a case statement, however this is only catching values that actually have something and ignoring the NULL valued fields. Because I am using the = clause in the WHERE I cannot do IS NULL. I do not want to have to write 2 IF statements because the stored procedure would then be enormous, so I want to know how to get null values as well. Here is my code:
SELECT
DATEPART(yy, DATEADD(mi, #Mdelta, d.DimDateValue)),
DisableCount = COUNT(*)
FROM
dbo.FactDisable AS f
JOIN
dbo.DimDate AS d ON f.DimDateId = d.DimDateId
JOIN
dbo.DimDevice AS v ON f.DimDeviceId = v.DimDeviceId
WHERE
d.DimDateValue >= #StartDateGMT
AND d.DimDateValue <= #EndDateGMT
AND f.IsTest = #IncludeTest
AND f.DimProductId = #DimProductId
AND v.DimBrowserId = CASE
WHEN #DimBrowserId = 0 THEN v.DimBrowserId
ELSE #DimBrowserId
END
GROUP BY
DATEPART(yy, DATEADD(mi, #Mdelta, d.DimDateValue))
The code is near the CASE clause.
Thanks
Change that line to be
AND (#DimBrowserID = 0 OR #DimBrowserID = v.DimBrowserId)
If #DimBroserID is 0 then no filtering will be applied for this line.
Use ISNULL:
SELECT DATEPART(yy,DATEADD(mi,#Mdelta,d.DimDateValue)),
DisableCount=COUNT(*)
FROM dbo.FactDisable AS f
JOIN dbo.DimDate AS d ON f.DimDateId = d.DimDateId
JOIN dbo.DimDevice AS v ON f.DimDeviceId = v.DimDeviceId
WHERE d.DimDateValue >= #StartDateGMT AND d.DimDateValue <= #EndDateGMT
AND f.IsTest = #IncludeTest AND f.DimProductId = #DimProductId
AND v.DimBrowserId = CASE WHEN ISNULL(#DimBrowserId,0) = 0 THEN v.DimBrowserId ELSE #DimBrowserId END
GROUP BY DATEPART(yy,DATEADD(mi,#Mdelta,d.DimDateValue))
CASE WHEN COALESCE(#MightBeNull, 0) = 0 THEN ZeroResult ...
will be treated as zero if #MightBeNull is null, and whatever #MightBeNull is if it's not null.
Assuming null means any browser, a better data model for this scenario might be to set an ID that identifies any browser, instead of setting it to null.
You probably know what you are running into is NULL does not equal NULL in a comparison.
Assuming you don't have control of the data model to fix that, one option would be to coalesce your NULL values to an unused id.
The resulting WHERE clause would look like this, assuming -1 is the unused value you choose.
AND COALESCE(v.DimBrowserId, -1) = CASE WHEN #DimBrowserId = 0 THEN COALESCE(v.DimBrowserId, -1) ELSE #DimBrowserId END

Error converting varchar to numeric with MSSQL

Query
SELECT TOP 1000
CASE WHEN VRI.Square_Footage <> ''
THEN VRI.Square_Footage
ELSE
CASE WHEN VRI.Property_Type = 'LAND'
THEN CAST((CONVERT(NUMERIC(38, 3),VRI.Acres)*43560) AS DECIMAL)
ELSE
VRI.Lot_Size
END
END
FROM View_Report_Information_Tables AS VRI
Even if I checked for VRI.Acres with isnumeric(), it still yield the same exact error? How can I fix this problem?
ISNUMERIC doesn't guarantee that it will successfully cast to decimal.
SELECT ISNUMERIC('£100') /*Returns 1*/
SELECT CONVERT(NUMERIC(38, 3),'£100') /*Error*/
Additionally all branches of the case statement need to return compatible datatypes. It looks like VRI.Square_Footage is a string.
Does this work for you?
SELECT TOP 1000 CASE
WHEN ISNUMERIC(VRI.Square_Footage + 'e0') = 1 THEN
VRI.Square_Footage
WHEN VRI.Property_Type = 'LAND'
AND ISNUMERIC(VRI.Acres + 'e0') = 1 THEN CAST((
CONVERT(NUMERIC(38, 3), VRI.Acres) * 43560 ) AS DECIMAL)
WHEN ISNUMERIC(VRI.Lot_Size + 'e0') = 1 THEN VRI.Lot_Size
END
FROM View_Report_Information_Tables AS VRI
Here run this
SELECT ISNUMERIC('d25')
That can be converted to float but not decimal/numeric
SELECT CONVERT(FLOAT,'2d5')
As you can see, you can't depend on numeric for decimal/numeric data types
Take a look at IsNumeric, IsInt, IsNumber for some code that will show you how you can check

Resources