Il semble que SQL Server considère que 0x et 0x00 valeurs égales:
SELECT CASE WHEN 0x = 0x00 THEN 1 ELSE 0 END
Cette sortie 1
.
Comment puis-je obtenir un vrai comportement de comparaison binaire binaire? aussi, quelles sont les règles exactes sous lesquelles deux (var)binary
Les valeurs sont considérées comme égales?
Notez également le comportement suivant:
--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])
Contexte de la question est que j'essaie de dédupliquer des données binaires. J'ai besoin de GROUP BY
Données binaires, non seulement comparer deux valeurs. Je suis content d'avoir même remarqué ce problème.
Remarque, que HASHBYTES
ne prend pas en charge les lecteurs. J'aimerais aussi trouver une solution plus simple.
Je n'ai pas pu trouver ce comportement de comparaison spécifié nulle part dans Bol.
Mais l'élément de connexion comparaison d'égalité non valide pour les données varbinaires avec zéros rembourrés droit
Fondamentalement, la norme laisse la mise en œuvre pour traiter les chaînes qui ne diffèrent que par [traînant]
00
comme égal ou moins. Nous le traitons comme égaux.
L'élément Connect indique également que la présence de zéros traînants est le seul cas dans lequel SQL Server diffère du comportement de comparaison octet-byte-octet.
Afin de distinguer deux valeurs binaires dans SQL Server qui ne diffèrent que par le suivi 0x00
caractères Vous pouvez également ajouter DATALENGTH
dans la comparaison comme indiqué dans votre question.
La raison de préférer DATALENGTH
plutôt que LEN
généralement ici est que ce dernier donne une extinction implicite à varchar
, puis vous obtenez le problème avec des espaces de fin.
+-------------+--------------------+
| LEN(0x2020) | DATALENGTH(0x2020) |
+-------------+--------------------+
| 0 | 2 |
+-------------+--------------------+
Bien que soit fonctionner dans votre cas d'utilisation.
Fait intéressant, les deux valeurs 0x0 et 0x00 ne sont que des représentations de caractères différentes pour la même valeur stockée. Essayez d'exécuter l'extrait suivant pour prouver cela à vous-même.
DECLARE @foo sql_variant
, @bar sql_variant
, @bat sql_variant
SET @foo = 0x0
SET @bar = 0x00
SET @bat = 0x00000000
SELECT 'foo' AS 'Var', @foo AS 'Value'
, SQL_VARIANT_PROPERTY(@foo, 'BaseType') AS 'BaseType'
, SQL_VARIANT_PROPERTY(@foo, 'Precisionh') AS 'Precision'
, SQL_VARIANT_PROPERTY(@foo, 'Scale') AS 'Scale'
, SQL_VARIANT_PROPERTY(@foo, 'MaxLength') AS 'MaxLength'
UNION
SELECT 'bar' AS 'Var', @bar
, SQL_VARIANT_PROPERTY(@bar, 'BaseType')
, SQL_VARIANT_PROPERTY(@bar, 'Precisionh')
, SQL_VARIANT_PROPERTY(@bar, 'Scale')
, SQL_VARIANT_PROPERTY(@bar, 'MaxLength')
UNION
SELECT 'bat' AS 'Var', @bat
, SQL_VARIANT_PROPERTY(@bat, 'BaseType')
, SQL_VARIANT_PROPERTY(@bat, 'Precisionh')
, SQL_VARIANT_PROPERTY(@bat, 'Scale')
, SQL_VARIANT_PROPERTY(@bat, 'MaxLength')
SELECT
CASE
WHEN @foo = @bar
THEN 'equal'
ELSE 'NOT EQUAL'
END AS TestResults
Je peux comprendre pourquoi le rembourrage zéro surprendrait les gens, mais cela a été le comportement par défaut depuis très longtemps, je suppose que je suis arrivé à y attendre.
-Patp