Trim automático do SQL Server do valor varchar em comparação igual, mas não comparável

13

Encontrei um comportamento interessante no SQL Server (observado em 2005 e 2012) hoje que esperava que alguém pudesse explicar.

Uma consulta que faz uma comparação usando =em um campo NVARCHAR ignorou o espaço à direita na sequência (ou aparou automaticamente o valor antes da comparação), mas a mesma consulta usando o likeoperador não ignorou o espaço. O agrupamento usado é Latin1_General_CI_AS em 2012.

Considere este SQL Fiddle: http://sqlfiddle.com/#!6/72262/4

Observe que o likeoperador não retorna um resultado para a sequência de espaço à direita, mas o =operador retorna . Por que é isso?

Pontos de bônus: não consigo replicar isso em um campo VARCHAR, eu pensaria que um espaço seria tratado da mesma maneira nos dois tipos de dados - isso é verdade?

WT_W
fonte
Eu estava olhando para escrever uma restrição de verificação de que uma corda foi cortada. Eu encontrei uma solução alternativa que é verificar isso, MyString+'x' = ltrim(rtrim(MyString))+'x'conforme sugerido neste blog
default.kramer

Respostas:

15

Minha resposta inicial sugeriu que o sinalizador ANSI_PADDING definido como OFF pode ser o culpado pela diferença de comportamento. No entanto, isso está incorreto; esse sinalizador afeta apenas o armazenamento, mas não a comparação de igualdade.

A diferença decorre da implementação do padrão SQL pela Microsoft . O padrão afirma que, ao verificar a igualdade, as duas strings esquerda e direita do operador de igualdade precisam ser preenchidas para ter o mesmo comprimento . Isso explica os seguintes resultados:

insert into test_padding (varchar_clmn, nvarchar_clmn) values ('space ', 'nspace ')
go
-- equality for varchar column
select count(*) from test_padding where varchar_clmn = 'space' -- returns 1
select count(*) from test_padding where varchar_clmn = 'space ' -- returns 1
select count(*) from test_padding where varchar_clmn = 'space    ' --returns 1
-- equality for nvarchar column
select count(*) from test_padding where nvarchar_clmn = 'nspace' -- returns 1
select count(*) from test_padding where nvarchar_clmn = 'nspace ' -- returns 1
select count(*) from test_padding where nvarchar_clmn = 'nspace    ' --returns 1

O operador LIKE não preenche seus operandos. Ele também se comporta de maneira diferente para os tipos VARCHARe NVARCHARcolunas :

-- likeness for varchar column
select count(*) from test_padding where varchar_clmn like 'space' -- returns 1
select count(*) from test_padding where varchar_clmn like 'space ' -- returns 1
select count(*) from test_padding where varchar_clmn like 'space    ' -- returns 0
-- likeness for nvarchar column
select count(*) from test_padding where nvarchar_clmn like 'nspace' -- returns 0
select count(*) from test_padding where nvarchar_clmn like 'nspace ' -- returns 1
select count(*) from test_padding where nvarchar_clmn like 'nspace    ' -- returns 0

O comportamento do operador LIKE para o tipo ASCII é específico do SQL Server; para o tipo Unicode, é compatível com ANSI.

Ralf
fonte
4

O SQL nasceu em uma época em que a maioria das linguagens de processamento de dados usava comprimentos fixos para cada campo / variável. O preenchimento automático de campos de texto com espaços extras também fazia parte dessa imagem. Para alinhar com esse comportamento, o tipo SQL CHAR original foi explicitamente definido para o operador '=' ignorar os espaços finais. (Se você acha isso estranho, mostre-me um caso convincente em que os espaços à direita anexados a um texto tenham um significado real nos negócios .)

Os tipos SQL CHAR evoluíram em todos os tipos de direções desde então, mas não é inconcebível que certos tipos de dados mais modernos ainda tenham herdado algumas características de seus predecessores históricos.

Erwin Smout
fonte
"mostre-me um caso convincente em que os espaços à direita anexados a um texto tenham um significado real de negócios" - armazenando dados significativos em espaço em branco, como determinadas saídas brutas do console e fragmentos XML não seguros.
Dai #
1

Na documentação de LIKE (Transact-SQL) , a Microsoft escreve (ênfase minha):

Correspondência de padrões usando LIKE

O LIKE suporta correspondência de padrões ASCII e correspondência de padrões Unicode. Quando todos os argumentos ... são tipos de dados de caracteres ASCII, a correspondência de padrões ASCII é executada. Se qualquer um dos argumentos for do tipo de dados Unicode, todos os argumentos serão convertidos em Unicode e a correspondência de padrões Unicode será executada. Quando você usa dados Unicode ... com LIKE, os espaços em branco à direita são significativos; no entanto, para dados não Unicode, os espaços em branco à direita não são significativos. O Unicode LIKE é compatível com o padrão ISO. ASCII LIKE é compatível com versões anteriores do SQL Server.

Michel de Ruiter
fonte