SQL Server 2014: How to cast a string value to int only if the value can be casted? - sql

I try to cast a string value in a field of a table to int, but only in the case that the value stores a value that can be casted to int (in the other case the original value must be returned). Example:
DECLARE #ErrorCode nvarchar(1024)
SET #ErrorCode = 'a10'
SELECT IIF(TRY_CAST(#ErrorCode AS int) IS NULL, #ErrorCode, CAST(#ErrorCode AS int))
I've seen similar codes on StackOverflow.
My problem is that the SQL Server (2014) does not seem to short-circuit, and executes the cast always, even if TRY_CAST(#ErrorCode AS int) results in NULL. The result of the code above is the error "Conversion failed when converting the nvarchar value 'a10' to data type int."
See this sample on rextester.com
I also tried other variants with the same result:
SELECT CASE WHEN TRY_CAST(#ErrorCode AS int) IS NULL THEN #ErrorCode ELSE (SELECT CAST(#ErrorCode AS int)) END
SELECT CASE TRY_CAST(#ErrorCode AS int) WHEN 1 THEN CAST(#ErrorCode AS int) ELSE #ErrorCode END
How can I achieve my goal (avoid the cast in case the value in #ErrorCode cannot be casted)?

The simple solution would be to use COALSECE:
DECLARE #ErrorCode nvarchar(1024)
SET #ErrorCode = 'a10'
SELECT COALSECE(CAST(TRY_CAST(#ErrorCode AS int) as nvarchar(1024)), #ErrorCode)
However, I don't see the point of casting to int and then back to nvarchar.

To validate NULL you should IS NULL
DECLARE #ErrorCode NVARCHAR(1024)
SET #ErrorCode = 'a10'
SELECT IIF(TRY_CAST(#ErrorCode AS int) IS NULL, #ErrorCode, CAST(CAST(#ErrorCode AS int) AS VARCHAR(50)))
You need to convert the INT again to VARCHAR again to avoid the implicit conversion. IIF returns the data type with the highest precedence from the types in true_value and false_value.

The problem I see is trying to hold 2 different types in a single column. I'm not sure how you plan to use this information, but you could split the values in to numeric and text columns based on the type. You can do an ISNUMERIC() check and CAST to INT if it's true, otherwise leave it as text, like so:
CREATE TABLE #ErrorCodes ( ErrorCode NVARCHAR(10) )
INSERT INTO #ErrorCodes
( ErrorCode )
VALUES ( '123' ),
( 'a10' ),
( 'bbb' ),
( '456' )
SELECT ErrorCode AS OriginalVal ,
CASE WHEN ISNUMERIC(ErrorCode) = 1 THEN CAST(ErrorCode AS INT)
ELSE NULL
END AS NumericVal ,
CASE WHEN ISNUMERIC(ErrorCode) = 0 THEN ErrorCode
ELSE NULL
END AS NonNumericVal
FROM #ErrorCodes
DROP TABLE #ErrorCodes
Produces:
OriginalVal NumericVal NonNumericVal
=====================================
123 123 NULL
a10 NULL a10
bbb NULL bbb
456 456 NULL

Related

Conversion failed when converting the varchar value '0:sval:' to data type int

Conversion failed when converting the varchar value '0:sval:' to data type int.
Please help, I'm getting this error message when looking for data for specific dates in my table.
My query:
SELECT *,
CAST(GETDATE() as DATE) as XTRA_REPORTED_DATE
FROM [RS].[REPORTS].[V_VALIDATOR_DIAGNOSTIC_EVENT_EXPLODED]
WHERE TXN_DATE_TIME BETWEEN '2021-09-28 22:13:36' AND '2021-09-28 22:13:37'
AND IS_OK=0
The function the table is using:
FUNCTION [REPORTS].[godValidatorSplit] (#inputString varchar(max), #isInputHex tinyint)
RETURNS #return TABLE (val varchar(max))
AS
BEGIN
DECLARE #xml xml
SET #xml = CONVERT(xml,'<v>'+
REPLACE(REPLACE(#inputString,',','</v><v>'),char(10),'')
+'</v>')
INSERT INTO #return(val)
SELECT CASE
WHEN (#isInputHex<>0)
THEN
CASE
WHEN (v.value('.','varchar(MAX)') NOT LIKE '%[^a-fA-F0-9]%')
THEN convert(bigint, convert(varbinary, '0x' + RIGHT('00000000'+v.value('.','varchar(MAX)'),8), 1))
ELSE 0
END
ELSE v.value('.','varchar(MAX)')
END
FROM #xml.nodes('/v') as a(v)
RETURN
END

Data not coming when old value is changed from null to other value

Select statement is not displaying data when I change value from 0 to null or vice versa.
But when I change data from 0 to 1 select statement starts displaying data.
Please find my code (query)
declare #tmptable TABLE (Id INT, IsVal BIT)
INSERT Into #tmptable VALUES(1,0)
--SELECT * FROM #tmptable
DECLARE #Id INT
DECLARE #IsVal BIT
SET #Id=1
SET #IsVal=NULL
select #Id as PrimaryKeyValue
,CAST(IsVal as VARCHAR) as OldValue,CAST(ISNULL(#IsVal,'') as VARCHAR) as NewValue
,'IsVal' AS DisplayFieldName,
CASE IsVal
WHEN 1 THEN 'Yes'
WHEN 0 THEN 'No'
END as DisplayOldValue
,CASE #IsVal
WHEN 1 THEN 'Yes'
WHEN 0 THEN 'No'
END as DisplayNewValue
from #tmptable WHERE Id =#Id and ISNULL(IsVal,'')<>ISNULL(#IsVal,'')
There is problem with statement :-
ISNULL(IsVal,'')<>ISNULL(#IsVal,'')
Can't figure out the change I need to make to the above statement so that my query can work as I desired. Please help.
#IsVal variable is used to set value.
Thanks
You are correct, the problem is this expression: ISNULL(IsVal,'')<>ISNULL(#IsVal,'')
When IsVal is 0 and #IsVal is NULL, this becomes:
0 <> ''
which will compare as integers, so the '' becomes 0 and you get:
0 <> 0
So, in your case, 0, '' and NULL will all be treated as equal. You need to choose an invalid int (maybe -1?) or cast the 0 to a varchar to do that comparison.
Thanks for the help,
I was able to resolve the issue:-
declare #tmptable TABLE (Id INT, IsVal BIT)
INSERT Into #tmptable VALUES(1,0)
--SELECT * FROM #tmptable
DECLARE #Id INT
DECLARE #IsVal BIT
declare #oldval VARCHAR(10)
SET #Id=1
SET #IsVal=null
select #oldval=isval from #tmptable WHERE Id=1
print ISNULL(#oldval,'')
print ISNULL(#IsVal,'')
--if(ISNULL(CAST(#oldval AS INT),'')<>ISNULL(CAST(#IsVal AS INT),''))
--BEGIN
PRINT '1'
select #Id as PrimaryKeyValue
,CAST(IsVal as VARCHAR(10)) as OldValue,CAST(ISNULL(#IsVal,'') as VARCHAR(10)) as NewValue
,'IsVal' AS DisplayFieldName,
CASE IsVal
WHEN 1 THEN 'Yes'
WHEN 0 THEN 'No'
END as DisplayOldValue
,CASE #IsVal
WHEN 1 THEN 'Yes'
WHEN 0 THEN 'No'
END as DisplayNewValue
from #tmptable WHERE Id =#Id and ISNULL(CAST(IsVal AS VARCHAR),'null')<>ISNULL(CAST(#IsVal AS VARCHAR),'null')
Why not just use a simple comparison?
(IsVal = #IsVal or IsVal IS NULL AND #IsVal IS NULL)
You may still have problems with type conversion, assuming the types are not compatible.
Why not just use a simple comparison?
(IsVal = #IsVal or IsVal IS NULL AND #IsVal IS NULL)
You may still have problems with type conversion, assuming the types are not compatible.
If that is the case:
(IsVal = CONVERT(VARCHAR(255), #IsVal) or
IsVal IS NULL AND #IsVal IS NULL
)
There is no need to invent special values for isnull() or coalesce().

Finding MAX value of data type Varchar

Firstly I have a table tblSample with ID as column of datatype INT. To auto generate ID for every transaction, I created a stored procedure:
DECLARE #Id INT
SELECT #Id = MAX(Id)
FROM tblSample
IF #Id IS NULL
BEGIN
SELECT 0 as Id
END
ELSE
SELECT MAX(Id) as ID FROM tblSample
Here as you observe if ID has no rows MAX(Id)=0 then return 0 or else return MAX(ID) value so that next insertion will be greater than max(ID).
That's fine but now I had column ID with datatype VARCHAR I have to do similar operation how can I that?
The code looks fine so it should work with VARCHAR also but my suggestion is to use storage variable also with same datatype so it won't get conflicted anywhere in the operation:
DECLARE #Id VARCHAR(10)
I think you could use MAX(CAST(varcharcolumn AS Int))
DECLARE #Id INT
SELECT #Id=MAX(Id) FROM tblSample
IF #Id IS NULL
BEGIN
SELECT 'Your_VarCharValue' + CAST(0 AS VARCHAR) as Id
END
ELSE
SELECT 'Your_VarCharValue' + CAST(MAX(Id) AS VARCHAR) as ID FROM tblSample

concat two integers and result as string in SQL

In table, 2 fields ID as int and Number as small int and i want to concatenate the two fields and display as string
eg: ID = 101 and Number = 9
output : 101.9
Dot to be added in between ID and Number?
How to query in SQL?
You can CAST your integer field to varchar and then concatenate them as you want.
DECLARE #ID INT
DECLARE #Number INT
SET #ID = 101
SET #Number = 9
SELECT CAST(#ID AS VARCHAR(10) ) +'.'+ CAST(#Number AS VARCHAR(10) )
In SQL 2012 (and later) I now find this easier using CONCAT (better performance too)
SELECT CONCAT(#ID, '.', #Number)
any NULL elements are converted to empty-strings preventing NULL propagation, which saves having to do the even more complex:
SELECT ISNULL(CAST(#ID AS VARCHAR(10) ), '') +'.'+ ISNULL(CAST(#Number AS VARCHAR(10) ) , '')

IsNull() on bigint's min value?

Why does the following expression in SQL Server return -9223372036854775808 and not 123?
I am calling this from a stored proc where I can't pass null parameters
declare #t bigint;
set #t = -9223372036854775808; --min value for bigint / long
select ISNULL(#t, 123)
Because:
IF #t IS NOT NULL
PRINT #t
ELSE
PRINT 123
Being negative doesn't mean the value is NULL. NULL is the lack of any value at all.
Because #t is not null.
What made you think that the most negative value for a bigint would be interpreted as null?
The ISNULL(#t, 123) function returns 123 if #t is NULL, otherwise it returns #t. You may want to do something like this.
NULLIF(#t, -9223372036854775808)
This will return NULL if #t equals -9223372036854775808. NULLIF returns the first expression (#t) if the two expressions are not equal.
To achieve what I think you want to achieve, try this:
declare #t bigint;
set #t = -9223372036854775808; --min value for bigint / long
select ISNULL(NULLIF(#t, -9223372036854775808) , 123)
or this:
declare #t bigint;
set #t = -9223372036854775808; --min value for bigint / long
select case #t when -9223372036854775808 then 123 else #t end
You seem to be assuming that -9223372036854775808 IS NULL which is incorrect. ISNULL(#t, 123) would only return NULL if #t IS NULL but it's not null since it has the value of -9223372036854775808 which is non-NULL.
ISNULL returns the first non-null value, they are both non-null (have value) so it returns the first one.
#t is not null because you assigned it a value. If you want ISNULL() to return 123, remove the assignment.
declare #t bigint;
select ISNULL(#t, 123)