SQL Server et la gestion des espaces en fin de chaîne (ou 'test' = 'test ')
Il s'agit d'une petite chose qu'il vaut mieux garder en tête quand on développe sur/pour SQL Server, et probablement d'autres SGBD si j'en crois la raison avancée que nous verrons plus bas.
C'est particulièrement surprennant pour quelqu'un ayant l'habitude de travailler avec d'autres langages, comme C#, qui n'ont pas ce genre de comportement.
Les chaînes (typées varchar, nvarchar) contenant des espaces en fin de chaîne sont considérées égales à leurs équivalents ne les possédant pas, et ce sur pratiquement pour toutes les opérations reposant sur ou utilisant une comparaison à l'exception de la partie droite d'une clause LIKE.
Ainsi ce script affichera 'true' :
declare @Str nvarchar(256);
declare @StrLW nvarchar(256);
set @Str = N'test';
set @StrLW = N'test ';
select case when @Str = @StrLW
then N'true'
else N'false'
end
Celui-ci ne sortira qu'une entrée dans le jeu de résultats, et ce sera probablement la valeur de @Str :
create table test (txt nvarchar(256));
insert into test (txt) values (@Str);
insert into test (txt) values (@StrLW);
select distinct txt from test;
Celui-ci (identique au précédent si ce n'est l'inversion des ordres INSERT) sortira probablement la valeur de @StrLW :
create table test (txt nvarchar(256));
insert into test (txt) values (@StrLW);
insert into test (txt) values (@Str);
select distinct txt from test;
(Avec une vraie table et une requête plus poussée la valeur extraite dépendra probablement des indexes mis en oeuvre.)
La raison invoquée pour expliquer ce comportement pour le moins étrange est une compatibilité avec la norme SQL-92 : INF: How SQL Server Compares Strings with Trailing Spaces
SQL Server follows the ANSI/ISO SQL-92 specification (Section 8.2, <Comparison Predicate>, General rules #3) on how to compare strings with spaces. The ANSI standard requires padding for the character strings used in comparisons so that their lengths match before comparing them. The padding directly affects the semantics of WHERE and HAVING clause predicates and other Transact-SQL string comparisons. For example, Transact-SQL considers the strings 'abc' and 'abc ' to be equivalent for most comparison operations.
Source : INF: How SQL Server Compares Strings with Trailing Spaces
Concernant LIKE, je vous laisse exécuter les 2 scripts ci-dessous (les différences entre les 2 résident dans les types utilisés pour les variables et les chaînes littérales) et observer less résultats :
declare @Str nvarchar(256);
declare @StrLW nvarchar(256);
set @Str = N'test';
set @StrLW = N'test ';
select N'true' where @StrLW like @Str;
select N'true' where @Str like @StrLW;
select N'true' where @StrLW like N'test';
select N'true' where @Str like N'test ';
declare @Str varchar(256);
declare @StrLW varchar(256);
set @Str = 'test';
set @StrLW = 'test ';
select N'true' where @StrLW like @Str;
select N'true' where @Str like @StrLW;
select N'true' where @StrLW like 'test';
select N'true' where @Str like 'test ';
Ca peut ouvrir la voie à des casses-têtes plus ou moins graves...
Autant ce comportement ne me choque pas, et je dirais même que je m'y attendais, pour un type à largeur fixe (char, nchar) autant pour un type à longueur variable (varchar, nvarchar) je ne m'y attendais vraiment pas.
Donc essayons de retenir cette spécificité pour éviter de la redécouvrir dans la douleur la prochaine fois !
Ce post vous a plu ? Ajoutez le dans vos favoris pour ne pas perdre de temps à le retrouver le jour où vous en aurez besoin :