web-dev-qa-db-ja.com

バイナリ0xと0x00を比較すると、SQL Serverで等しいことが判明

SQL Serverは0xと0x00を同じ値と見なしているようです:

SELECT CASE WHEN 0x = 0x00 THEN 1 ELSE 0 END

これは1

真のバイナリビットごとの比較動作を取得するにはどうすればよいですか?また、正確なルールとは、2つの(var)binary値は等しいと見なされますか?

次の動作にも注意してください。

--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])

質問の背景は、バイナリデータを重複排除しようとしていることです。する必要がある GROUP BYバイナリデータ。2つの値を比較するだけではありません。この問題に気付いてよかったです。

HASHBYTESはLOBをサポートしないことに注意してください。もっと簡単な解決策も見つけたいです。

5
usr

BOLのどこにも指定されているこの比較動作を見つけることができませんでした。

しかし、接続項目 右にゼロが埋め込まれたvarbinaryデータの無効な等値比較 は、

基本的に、標準では、[trailing] 00のみが異なる文字列を等しいかそれ以下として処理する実装に任せています。私たちはそれを同じものとして扱います。

接続項目は、後続ゼロの存在がSQL Serverがバイトごとの比較動作と異なる唯一のケースであることも述べています。

末尾の0x00文字のみが異なるSQL Serverの2つのバイナリ値を区別するために、質問に示されているように、比較にDATALENGTHを追加することもできます。

ここでは、一般的にDATALENGTHではなくLENを優先する理由は、後者がvarcharへの暗黙のキャストを提供し、末尾のスペースに関する問題が発生するためです。

+-------------+--------------------+
| LEN(0x2020) | DATALENGTH(0x2020) |
+-------------+--------------------+
|           0 |                  2 |
+-------------+--------------------+

どちらもあなたのユースケースで機能します。

3
Martin Smith

興味深いことに、2つの値0x0と0x00は、同じ格納された値の単なる異なる文字表現です。次のスニペットを実行して、これを自分で証明してみてください。

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

ゼロパディングがなぜ人々を驚かせるのかは理解できますが、それは非常に長い間デフォルトの動作でしたので、私はそれを期待するようになったと思います。

-PatP

2
Pat Phelan