Reputation: 83
I have a variable like this
DECLARE @CODE NVARCHAR(10) = '09000:09502';
I need to split the @CODE
variable into two variables and insert them into a temporary table for doing bulk insert.
But when I using 'CASE WHEN' inside my select statement, the value after split will remove the leading zero, '09000' will became '9000' (seem like those value is treat as number instead of string). Even I using CAST function, it is still not working.
I doing a little testing using this code:
DECLARE @CODE VARCHAR(10) = '09000:09502';
DECLARE @Split1 VARCHAR(10) = '';
DECLARE @Split2 VARCHAR(10) = '';
SET @Split1 = CAST((CASE WHEN CHARINDEX(':', @CODE) > 0
THEN LEFT(@CODE, CHARINDEX(':', @CODE) - 1)
ELSE -1
END) AS VARCHAR(20))
SET @Split2 = LEFT(@CODE, 5);
PRINT(@Split1);
PRINT(@Split2);
The output I get is:
9000
09000
When I didn't using 'CASE WHEN', I can get the value what I want to, but I using 'CASE WHEN', the leading zero will be removed.
How can I preserve the leading zero value when I use CASE WHEN
and LEFT
function in a SQL Server stored procedure?
Thanks in advance.
Upvotes: 2
Views: 1194
Reputation: 34217
You should probably just make your conversion impervious to the values, Here are some test cases: The second query is the one you can use with just the two columns, INSERT
or UPDATE
as you see fit
DECLARE @Codes TABLE (Code VARCHAR(20));
INSERT INTO @Codes (Code)
Values('09000:09502'),('090001:09502'),('090001:095022'),('0900022:09502'),
('090001:095021'),('0900055'),(':0900056'),('090003:'),(''),(':'),('::'),
('8:0900055'),(NULL);
DECLARE @Splitter VARCHAR(1) = ':';
SELECT
Code,
CHARINDEX(@Splitter, Code) AS SplitPoint,
CASE
WHEN CHARINDEX(@Splitter, Code) = 0 THEN 'NO splitter'
WHEN CHARINDEX(@Splitter, Code) = 1 THEN 'NO LEFT'
WHEN CHARINDEX(@Splitter, Code) > 1 THEN
LEFT(Code, CHARINDEX(@Splitter, Code) - 1)
WHEN CHARINDEX(@Splitter, Code) IS NULL THEN 'OOPS'
ELSE 'broken'
END AS Split1
,
CASE
WHEN CHARINDEX(@Splitter, Code) = 0 THEN Code
WHEN CHARINDEX(@Splitter, Code) = 1 THEN RIGHT(Code,LEN(Code)- 1)
WHEN CHARINDEX(@Splitter, Code) > 1 THEN
RIGHT(Code, LEN(Code )-1 -
LEN(LEFT(Code, CHARINDEX(@Splitter, Code) - 1))
)
WHEN CHARINDEX(@Splitter, Code) IS NULL THEN 'OOPS2'
WHEN CHARINDEX(@Splitter, Code) > 1 THEN 'NO RIGHT'
ELSE RIGHT(Code, LEN(Code)) + 'faile'
END AS Split2
,
CASE
WHEN CHARINDEX(@Splitter, Code) = 0 THEN ' no splitter'
WHEN CHARINDEX(@Splitter, Code) = 1 THEN ' =1'
WHEN CHARINDEX(@Splitter, Code) > 1 THEN ' >1'
WHEN CHARINDEX(@Splitter, Code) IS NULL THEN 'OOPS2'
WHEN CHARINDEX(@Splitter, Code) > 1 THEN 'NO RIGHT'
ELSE RIGHT(Code, LEN(Code)) + 'faile'
END AS Split2By
FROM @Codes;
-- end code
CREATE TABLE #MyTemp (Split1 VARCHAR(20),Split2 VARCHAR(20));
INSERT INTO #MyTemp (Split1, Split2)
SELECT
CASE
WHEN CHARINDEX(@Splitter, Code) = 0 THEN ''
WHEN CHARINDEX(@Splitter, Code) = 1 THEN ''
WHEN CHARINDEX(@Splitter, Code) > 1 THEN LEFT(Code, CHARINDEX(@Splitter, Code) - 1)
WHEN CHARINDEX(@Splitter, Code) IS NULL THEN Code
ELSE Code -- 'broken'
END AS Split1
,
CASE
WHEN CHARINDEX(@Splitter, Code) = 0 THEN Code
WHEN CHARINDEX(@Splitter, Code) = 1 THEN RIGHT(Code,LEN(Code)- 1)
WHEN CHARINDEX(@Splitter, Code) > 1 THEN RIGHT(Code, LEN(Code )-1 - LEN(LEFT(Code, CHARINDEX(@Splitter, Code) - 1)))
WHEN CHARINDEX(@Splitter, Code) IS NULL THEN Code
WHEN CHARINDEX(@Splitter, Code) > 1 THEN ''
ELSE Code -- 'fail'
END AS Split2
FROM TableWithUnsplitCodes;
SELECT * FROM #MyTemp
-- WHERE --clause if you need to bypass any
Upvotes: 0
Reputation: 164174
All branches of a CASE
statement must return the same data type.
When you return -1
at the else part, the value returned by this CASE is casted to integer so 09000
will turn to 9000
.
You can change -1
to '-1'
.
DECLARE @CODE VARCHAR(11) = '09000:09502';
DECLARE @Split1 VARCHAR(10) = '';
DECLARE @Split2 VARCHAR(10) = '';
SET @Split1 = CASE
WHEN CHARINDEX(':',@CODE)>0 THEN LEFT(@CODE, CHARINDEX(':', @CODE)-1)
ELSE '-1'
END
SET @Split2 = RIGHT(@CODE, LEN(@CODE)-CHARINDEX(':', @CODE));
PRINT(@Split1);
PRINT(@Split2);
This way you don't need the CAST()
function.
Also you declared @CODE
as VARCHAR(10)
and this truncated the last char.
Change to VARCHAR(11)
.
Also I guess you want @Split2
to be assigned the right 5 chars of @CODE
and not the left as in your code.
See the demo.
Upvotes: 2
Reputation: 858
As @Arulkumar mentioned, it is because your case statement is returning an integer. I simplified your code a bit:
DECLARE @CODE VARCHAR(10) = '09000:09502';
DECLARE @Split1 VARCHAR(10) = '';
DECLARE @Split2 VARCHAR(10) = '';
DECLARE @ColonIndex INT = CHARINDEX(':',@CODE)
SET @Split1 = CASE WHEN @ColonIndex > 0 THEN LEFT(@CODE, @ColonIndex-1)
ELSE '-1' END
SET @Split2 = LEFT(@CODE, 5);
PRINT(@Split1);
PRINT(@Split2);
Result:
Upvotes: 1
Reputation: 13237
In your CASE statement, the THEN
and ELSE
statement's result data type should be same. But in your query the ELSE block's return result is -1
, so it considering the output of the case statement is INT
, so it remove the leading zero from the result and return as integer, and you are expecting the output as varchar only.
So if you are modify your ELSE
block to ELSE '' END
or ELSE '-1' END
it will return your expected result as varchar(10).
Upvotes: 1