Parece que o SQL Server considera 0x e 0x00 valores iguais:
SELECT CASE WHEN 0x = 0x00 THEN 1 ELSE 0 END
Isso gera 1
.
Como posso obter um verdadeiro comportamento de comparação bit a bit binário? Além disso, quais são as regras exatas sob as quais dois (var)binary
valores são considerados iguais?
Observe também o seguinte comportamento:
--prints just one of the values
SELECT DISTINCT [Data]
FROM (VALUES (0x), (0x00), (0x0000)) x([Data])
--prints the obvious length values 1, 2 and 3
SELECT DATALENGTH([Data]) AS [DATALENGTH], LEN([Data]) AS [LEN]
FROM (VALUES (0x), (0x00), (0x0000)) x([Data])
O pano de fundo da questão é que estou tentando deduplicar dados binários. Eu preciso de GROUP BY
dados binários, não apenas comparar dois valores. Estou feliz por ter notado esse problema.
Observe que HASHBYTES
isso não oferece suporte a LOBs. Eu também gostaria de encontrar uma solução mais simples.
Não consegui encontrar esse comportamento de comparação especificado em nenhum lugar no BOL.
Mas a comparação de igualdade Connect Item Invalid para dados varbinary com zeros preenchidos à direita afirma que
O Connect Item também informa que a presença de zeros à direita é o único caso em que o SQL Server difere do comportamento de comparação byte a byte.
Para distinguir entre dois valores binários no SQL Server que diferem apenas por
0x00
caracteres à direita, você também pode adicionarDATALENGTH
à comparação, conforme indicado em sua pergunta.A razão para preferir
DATALENGTH
em vez deLEN
geralmente aqui é porque o último dá uma conversão implícita paravarchar
e então você tem o problema com os espaços à direita.Embora qualquer um funcione no seu caso de uso.
Curiosamente, os dois valores 0x0 e 0x00 são apenas representações de caracteres diferentes para o mesmo valor armazenado. Tente executar o trecho a seguir para provar isso a si mesmo.
Posso entender por que o preenchimento zero surpreenderia as pessoas, mas esse tem sido o comportamento padrão há muito tempo, então acho que já esperava isso.
-PatP