J'ai la requête suivante:
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
Assez simple – je teste une requête de partage de nom. Donc, je teste le scénario où le nom n'a pas d'espaces et je reçois l'exception suivante:
Paramètre de longueur non valide transmis à la fonction
SUBSTRING
.
Pourquoi donc? Ne devrait-il pas évaluer la première clause et passer immédiatement à l' ELSE
? Comment puis-je contourner cela..?
L'optimiseur est assez intelligent pour remarquer que vous avez une expression constante et essayez de l'évaluer. Passer la constante à travers une variable la ferait tourner:
DECLARE @TestSsortingng nvarchar(100) = 'Sara'; SELECT CASE WHEN @TestSsortingng like '% %' THEN SUBSTRING(@TestSsortingng, 1, CHARINDEX(' ', @TestSsortingng) - 1) ELSE @TestSsortingng END AS FirstName, CASE WHEN @TestSsortingng like '% %' THEN SUBSTRING(@TestSsortingng, CHARINDEX(' ', @TestSsortingng) + 1, 8000) ELSE '' END AS LastName
Pour répondre à la question, le processeur ne calculerait THEN
que si WHEN
est vrai , sinon il calculera uniquement l'expression ELSE
. Mais avant même que Optimizer ne tente de replace toutes les expressions constantes par des valeurs calculées, Processor ne devra pas les recalculer pour chaque ligne. C'est ce qu'on appelle " Constant Folding ".
En utilisant une variable fonctionne;
DECLARE @NameSsortingng varchar(10); SET @NameSsortingng = 'Sara' SELECT CASE WHEN @NameSsortingng like '% %' THEN SUBSTRING(@NameSsortingng, 1, CHARINDEX(' ', @NameSsortingng) - 1) ELSE @NameSsortingng END AS FirstName, CASE WHEN @NameSsortingng like '% %' THEN SUBSTRING(@NameSsortingng, CHARINDEX(' ', @NameSsortingng) + 1, 8000) ELSE '' END AS LastName
Le problème avec votre code est qu'il vérifie que chaque partie fonctionnera lorsqu'une valeur statique est transmise. Il n'aime pas que CHARINDEX(' ', 'Sara') - 1
résout égal à -1. Un hack pour contourner ce serait d'envelopper cette fonction dans la fonction ABS()
;
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