2009-07-17 4 views
0

J'ai une table créée avec:Pourquoi aurait SQLServer instruction select sélectionner des lignes qui correspondent et des lignes correspondant à et ont des espaces de fin

SET ANSI_NULLS ON 
GO 
SET QUOTED_IDENTIFIER ON 
GO 
SET ANSI_PADDING ON 
GO 
CREATE TABLE [dbo].[TestFeature1](
[Id] [nvarchar](50) NOT NULL, 
[Leng] [decimal](18, 0) NOT NULL 
) ON [PRIMARY] 

GO 
SET ANSI_PADDING OFF 

J'inséré des données avec ceci:

insert into TestFeature1 (id,leng) values ('1',100); 
insert into TestFeature1 (id,leng) values ('1 ',1000); 

Lorsque je sélectionne à partir de la table avec celle-ci:

select * from TestFeature1 where id='1'; 

cela renvoie 2 rangs

1 100 
1 1000 

pourquoi cela serait-il? pourquoi retourne-t-il la version avec l'espace à la fin même quand la requête spécifie que la valeur est seulement 1 seule, sans espace? LEN() est dangereux pour tester ANSI_PADDING car il est défini pour renvoyer la longueur en excluant les espaces de fin, et DATALENGTH() est préférable comme AdaTheDev dit:

+0

Pour votre information, si vous mettez une clé primaire sur votre deuxième insert [Id] échouera comme un double –

Répondre

2

Fait intéressant, fonctionne si vous utilisez LIKE:

select * from TestFeature1 where id LIKE '1' 

Edit: après un peu plus de recherches que je trouve d'autres ont eu pour nous la même conversation. Voir here. Ce commentaire est à mi-chemin de la discussion. Mais le résultat était tel que nous l'avons trouvé, soit utiliser LIKE comme démontré ci-dessus, soit ajouter une deuxième condition pour vérifier la DATALENGTH de la colonne et la valeur fournie sont les mêmes. Je préfère la route LIKE.

3

Pour retravailler ma réponse, LEN() est dangereux pour tester ANSI_PADDING.

Ce qui est intéressant, c'est que ANSI_PADDING est un paramètre d'insertion et qu'il est honoré pour VARCHAR, mais pas pour NVARCHAR. Deuxièmement, si vous renvoyez une colonne avec des espaces de fin, ou si vous utilisez le '=' pour l'égalité, il semble y avoir une troncature implicite de l'espace de fin qui se produit.

SET ANSI_NULLS ON 
GO 
SET QUOTED_IDENTIFIER ON 
GO 
SET ANSI_PADDING OFF 
GO 
CREATE TABLE [dbo].[TestFeature1](
[Id] [varchar](50) NOT NULL, 
[Leng] [decimal](18, 0) NOT NULL 
) ON [PRIMARY] 

GO 

insert into TestFeature1 (id,leng) values ('1',100); insert into TestFeature1 (id,leng) values ('1 ',1000); 

-- verify no spaces inserted at end 
select '['+id+']', * from TestFeature1 
select datalength(id), * from TestFeature1 
go 

DROP TABLE [dbo].[TestFeature1] 
go 
SET ANSI_NULLS ON 
GO 
SET QUOTED_IDENTIFIER ON 
GO 
SET ANSI_PADDING OFF 
GO 
CREATE TABLE [dbo].[TestFeature1](
[Id] [nvarchar](50) NOT NULL, 
[Leng] [decimal](18, 0) NOT NULL 
) ON [PRIMARY] 

GO 

insert into TestFeature1 (id,leng) values ('1',100); insert into TestFeature1 (id,leng) values ('1 ',1000); 

-- verify spaces inserted at end, and ANSI_PADDING OFF was not honoured by NVARCHAR 
select '['+id+']', * from TestFeature1 
select datalength(id), * from TestFeature1 
go 
+0

Ils ne tronque pas les espaces de fin. par exemple. essayez: SELECT '[' + id + ']', * FROM @Data où id = '1' qui montrera l'espace est toujours là - plutôt LEN() fait un trim – AdaTheDev

+0

Je crois que l'instruction ANSI_PADDING contrôle la troncature des espaces de fin sur l'insertion.Le varchar/nvarchar indique si le texte est unicode ou non –

+0

Si vous utilisez DATALENGTH() au lieu de LEN(), cela l'indique également - les longueurs seront 2 et 4 (nvarchar = 2 octets par caractère) – AdaTheDev

1

Rechercher this thread. Fait pour une lecture très intéressante sur ce sujet.

Raj

1

Je n'aime vraiment pas une pièce d'identité pour être une si grande colonne de longueur variable, et je vais essayer d'éviter cela. Toutefois, si vous avez vraiment besoin que cela fonctionne, ajoutez une colonne calculée à votre table où vous préfixe et le suffixe de la colonne avec des tubes comme:

ALTER TABLE TestFeature1 ADD 
    IDx AS '|'+ID+'|' PERSISTED 

Cela forcera l'ensemble de la chaîne à comparer à l'autre, étant donné ne sera jamais un caractère principal ou final. Vous pouvez indexer cela aussi.

vous utiliseriez code comme ceci:

select * from TestFeature1 where id='|1|'; 
select * from TestFeature1 where id='|1 |'; 
Questions connexes