I have the following query:
SELECT
CASE
WHEN 'Sara' like '% %' THEN SUBSTRING('Sara', 1, CHARINDEX(' ', 'Sara') - 1)
ELSE 'Sara'
END AS FirstName,
CASE
WHEN 'Sara' like '% %' THEN SUBSTRING('Sara', CHARINDEX(' ', 'Sara') + 1, 8000)
ELSE ''
END AS LastName
Pretty straight-forward - I'm testing a name split query. So I test the scenario where the name has no spaces and I get the following exception:
Invalid length parameter passed to the
SUBSTRING
function.
Why is that? Should it not evaluate the first clause and immediate go to the ELSE
? How do I get around this..?
To close that gap, SQL uses the order in which the conditions appear in the case expression to define their precedence. 0 Put simply: case expressions evaluate to the <result> of the first true <condition> .
The CASE statement selects a sequence of statements to execute. To select the sequence, the CASE statement uses a selector (an expression whose value is used to select one of several alternatives) or, in the searched CASE statement, multiple search conditions.
CASE WHEN takes in values, checks them against a condition and THEN outputs values into a new column based on if it satisfies the condition. Note: CASE WHEN statements will always output new values to a new column which is different than “if then” which can replace values in the same column.
Multiple conditions in CASE statementYou can evaluate multiple conditions in the CASE statement.
Optimizer is smart enough to notice you have constant expression there and try to evaluate it. Passing the constant through a variable would trick it to run:
DECLARE @TestString nvarchar(100) = 'Sara';
SELECT
CASE
WHEN @TestString like '% %'
THEN SUBSTRING(@TestString, 1, CHARINDEX(' ', @TestString) - 1)
ELSE @TestString
END AS FirstName,
CASE
WHEN @TestString like '% %'
THEN SUBSTRING(@TestString, CHARINDEX(' ', @TestString) + 1, 8000)
ELSE ''
END AS LastName
To answer the question, Processor would calculate THEN
expression only if WHEN
is true, otherwise it will calculate only ELSE
expression. But even before that Optimizer would try to substitute all constant expressions with calculated values so that Processor won't have to re-calculate them for each row. It's called "Constant Folding".
Using a variable works;
DECLARE @NameString varchar(10); SET @NameString = 'Sara'
SELECT
CASE
WHEN @NameString like '% %' THEN SUBSTRING(@NameString, 1, CHARINDEX(' ', @NameString) - 1)
ELSE @NameString
END AS FirstName,
CASE
WHEN @NameString like '% %' THEN SUBSTRING(@NameString, CHARINDEX(' ', @NameString) + 1, 8000)
ELSE ''
END AS LastName
The issue with your code is that it checks that each part will work when a static value is passed. It doesn't like that CHARINDEX(' ', 'Sara') - 1
resolves to equal -1. A hack to get around this would be to wrap this function in the ABS()
function;
SELECT
CASE
WHEN 'Sara' like '% %' THEN SUBSTRING('Sara', 1, ABS(CHARINDEX(' ', 'Sara') - 1))
ELSE 'Sara'
END AS FirstName,
CASE
WHEN 'Sara' like '% %' THEN SUBSTRING('Sara', CHARINDEX(' ', 'Sara') + 1, 8000)
ELSE ''
END AS LastName
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With