Pergunta

Encontrei algo um pouco estranho esta manhã e pensei em enviá-lo para comentário.

Alguém pode explicar por que a seguinte consulta SQL imprime 'igual' quando executada no SQL 2008.O nível de compatibilidade do banco de dados está definido como 100.

if '' = ' '
    print 'equal'
else
    print 'not equal'

E isso retorna 0:

select (LEN(' '))

Parece estar cortando automaticamente o espaço.Não tenho ideia se esse era o caso nas versões anteriores do SQL Server e não tenho mais ninguém para testá-lo.

Encontrei isso porque uma consulta de produção estava retornando resultados incorretos.Não consigo encontrar esse comportamento documentado em nenhum lugar.

Alguém tem alguma informação sobre isso?

Foi útil?

Solução

varcharS e a igualdade são espinhosas em tsql. o LEN função diz:

Retorna o número de caracteres, em vez do número de bytes, da expressão de string fornecida, excluindo espaços em branco à direita.

Você precisa usar DATALENGTH Para conseguir um verdadeiro byte contagem dos dados em questão. Se você tiver dados Unicode, observe que o valor que você obtém nessa situação não será o mesmo que o comprimento do texto.

print(DATALENGTH(' ')) --1
print(LEN(' '))        --0

Quando se trata de igualdade de expressões, as duas seqüências são comparadas para a igualdade como esta:

  • Obtenha uma corda mais curta
  • Almofada com espaços em branco Até o comprimento igual ao de uma corda mais longa
  • Compare os dois

É o passo do meio que está causando resultados inesperados - depois dessa etapa, você está efetivamente comparando o espaço em branco contra o espaço em branco - portanto, eles são vistos como iguais.

LIKE se comporta melhor do que = Na situação "em branco", porque ela não executa em branco no padrão que você estava tentando combinar:

if '' = ' '
print 'eq'
else
print 'ne'

Darei eq enquanto:

if '' LIKE ' '
print 'eq'
else
print 'ne'

Darei ne

Cuidado com LIKE No entanto: não é simétrico: trata o espaço de branco à direita como significativo no padrão (RHS), mas não na expressão de correspondência (LHS). O seguinte é retirado de aqui:

declare @Space nvarchar(10)
declare @Space2 nvarchar(10)

set @Space = ''
set @Space2 = ' '

if @Space like @Space2
print '@Space Like @Space2'
else
print '@Space Not Like @Space2'

if @Space2 like @Space
print '@Space2 Like @Space'
else
print '@Space2 Not Like @Space'

@Space Not Like @Space2
@Space2 Like @Space

Outras dicas

O = operador é T-SQL não é tanto "igual" como é "são a mesma palavra/frase, de acordo com o agrupamento do contexto da expressão", e Len é "o número de caracteres na palavra/frase". Nenhuma colação trata os espaços em branco como parte da palavra/frase que os precede (embora eles tratem os espaços em branco como parte da corda que precedem).

Se você precisar distinguir 'isto' de 'isto', não deverá usar o operador "são a mesma palavra ou frase" porque 'isto' e 'isto' são a mesma palavra.

Contribuindo para o modo como = funciona está a ideia de que o operador de igualdade de strings deve depender do conteúdo de seus argumentos e do contexto de agrupamento da expressão, mas não deve depender dos tipos de argumentos, se ambos forem tipos de string .

O conceito de linguagem natural de "estas são a mesma palavra" normalmente não é preciso o suficiente para poder ser capturado por um operador matemático como =, e não há conceito de tipo de string em linguagem natural.O contexto (ou seja, agrupamento) é importante (e existe na linguagem natural) e faz parte da história, e propriedades adicionais (algumas que parecem peculiares) fazem parte da definição de = para torná-lo bem definido no mundo não natural de dados.

Na questão do tipo, você não gostaria que as palavras mudassem quando fossem armazenadas em diferentes tipos de string.Por exemplo, os tipos VARCHAR(10), CHAR(10) e CHAR(3) podem conter representações da palavra 'gato' e ?= 'cat' deve nos permitir decidir se um valor de qualquer um desses tipos contém a palavra 'cat' (com questões de maiúsculas e minúsculas e acento determinadas pela ordenação).

Resposta ao comentário de JohnFx:

Ver Usando dados char e varchar em livros on-line.Citando essa página, enfatize a minha:

Cada valor de dados char e varchar possui um agrupamento.As colações definem atributos como os padrões de bits usados ​​para representar cada caractere, regras de comparação, e sensibilidade a maiúsculas e minúsculas ou acentuação.

Concordo que poderia ser mais fácil de encontrar, mas está documentado.

Vale a pena notar também que a semântica do SQL, onde = tem a ver com os dados do mundo real e o contexto da comparação (em oposição a algo sobre bits armazenados no computador), faz parte do SQL há muito tempo.A premissa dos RDBMSs e SQL é a representação fiel de dados do mundo real, daí o seu suporte para agrupamentos muitos anos antes de ideias semelhantes (como CultureInfo) entrarem no domínio das linguagens do tipo Algol.A premissa dessas linguagens (pelo menos até muito recentemente) era a resolução de problemas em engenharia, e não o gerenciamento de dados de negócios.(Recentemente, o uso de linguagens semelhantes em aplicações não relacionadas à engenharia, como a pesquisa, está fazendo alguns avanços, mas Java, C# e assim por diante ainda estão lutando com suas raízes não comerciais.)

Na minha opinião, não é justo criticar o SQL por ser diferente da "maioria das linguagens de programação". O SQL foi projetado para suportar uma estrutura para modelagem de dados de negócios muito diferente da engenharia, para que o idioma seja diferente (e melhor para seu objetivo).

Caramba, quando o SQL foi especificado pela primeira vez, algumas linguagens não tinham nenhum tipo de string integrado.E ainda em alguns idiomas, o operador igual entre strings não compara dados de caracteres, mas compara referências!Não me surpreenderia se em mais uma ou duas décadas a ideia de que == depende da cultura se tornasse a norma.

Eu achei isto Artigo do blog que descreve o comportamento e explica o porquê.

O padrão SQL requer que as comparações de string, efetivamente, façam a corda mais curta com caracteres espaciais.Isso leva ao resultado surpreendente de que n '' = n '' (a sequência vazia é igual a uma string de um ou mais caracteres espaciais) e, mais geralmente, qualquer string é igual a outra string se diferir apenas por espaços à direita. Isso pode ser um problema em alguns contextos.

Mais informações também disponíveis em MSKB316626

Havia uma pergunta semelhante há algum tempo, onde eu olhei para um problema semelhante aqui

Em vez de len (''), use Datallength ('') - que fornece o valor correto.

As soluções deveriam usar uma cláusula semelhante, conforme explicado na minha resposta, e/ou incluir uma segunda condição na cláusula WHERE para verificar também o comprimento do datal.

Leia essa pergunta e links lá.

Para comparar um valor com um espaço literal, você também pode usar essa técnica como uma alternativa à declaração semelhante:

IF ASCII('') = 32 PRINT 'equal' ELSE PRINT 'not equal'

Às vezes, é preciso lidar com espaços nos dados, com ou sem outros caracteres, mesmo que a idéia de usar o NULL seja melhor - mas nem sempre utilizável. Eu encontrei a situação descrita e resolvi da seguinte maneira:

... onde ('>' + @space + '<') <> ('>' + @space2 + '<')

É claro que você não faria essa grande quantidade de dados FPR, mas funciona rápido e fácil para algumas centenas de linhas ...

Herbert

Como fazer registros distintos em Selecionar com os campos char/varchar no servidor SQL: Exemplo:

declare @mayvar as varchar(10)

set @mayvar = 'data '

select mykey, myfield from mytable where myfield = @mayvar

esperado

mykey (int) | Myfield (Varchar10)

1 | 'dados '

obtido

myKey | myfield

1 | 'dados' 2 | 'dados '

Mesmo se eu escreverselect mykey, myfield from mytable where myfield = 'data' (sem espaço em branco final) Recebo os mesmos resultados.

Como eu resolvi? Neste modo:

select mykey, myfield
from mytable
where myfield = @mayvar 
and DATALENGTH(isnull(myfield,'')) = DATALENGTH(@mayvar)

E se houver um índice no MyField, ele será usado em cada caso.

Espero que seja útil.

Outra maneira é colocá -lo de volta em um estado que o espaço tem valor. por exemplo: substitua o espaço por um personagem conhecido como o _

if REPLACE('hello',' ','_') = REPLACE('hello ',' ','_')
    print 'equal'
else
    print 'not equal'

Retornos: não é igual

Não é o ideal e provavelmente lento, mas é outro caminho rápido quando necessário rapidamente.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top