如何在两个二进制类型之间的sql server中进行按位异或?

时间:2011-01-28 22:48:47

标签: sql sql-server tsql

根据此链接: Bitwise Operators (Transact-SQL) 我们可以在binary和int,smallint,tinyint之间进行按位运算,反之亦然。

但是如何在两个二进制类型之间的sql server中进行按位异或? 或者,如果这不可能,我如何将二进制/ varbinary拆分为单个字节?

我要求这个的原因是因为我需要xor两个大于max int值的数字。 感谢。

4 个答案:

答案 0 :(得分:6)

代码块中的所有注释

-- variables
declare @vb1 binary(16), @vb2 binary(16), @lo binary(8), @hi binary(8)

-- 2 guids to compare
declare @guid1 uniqueidentifier set @guid1 = '96B4316D-1EA7-4CA3-8D50-FEE8047C1329'
declare @guid2 uniqueidentifier set @guid2 = 'FFFFFFFF-FFFF-FFFF-FFFF-FFFFFFFFFFFF'

-- split every 8 bytes into a binary(8), which is a bigint, the largest size usable with XOR
select @vb1 = @guid1, @vb2 = @guid2

-- xor the high and low parts separately
select @hi = convert(binary(8), substring(@vb1,1,8)) ^ convert(bigint, substring(@vb2,1,8))
select @lo = convert(binary(8), substring(@vb1,9,8)) ^ convert(bigint, substring(@vb2,9,8))

-- the final result, concatenating the bytes using char(8) - binary -> uniqueidentifier
select 'A', @guid1 union all
select 'B', @guid2 union all
select 'A XOR B = ', convert(uniqueidentifier, convert(binary(16),convert(char(8),@hi) + convert(char(8),@lo)))

答案 1 :(得分:2)

根据Bitwise Exclusive OR documentation

  

注意

     

只有一个表达式可以是二进制或varbinary数据类型   按位操作。

答案 2 :(得分:2)

Martin提出的问题中的评论给了我一个如何拆分二进制文件的想法,这样我就可以对值进行异或。 最初我想在sql中对两个GUID进行异或。所以这是我带来的代码:

declare @guid1 uniqueidentifier
declare @guid2 uniqueidentifier
declare @guid3_hi binary(8)
declare @guid3_lo binary(8)
declare @guid3_temp varchar(32)
declare @guid3_char varchar(36)
declare @guid3 uniqueidentifier

set @guid1 = '96B4316D-1EA7-4CA3-8D50-FEE8047C1329'
set @guid2 = 'FFFFFFFF-FFFF-FFFF-FFFF-FFFFFFFFFFFF'

set @guid3_hi = CAST(SUBSTRING(CAST(@guid1 as binary(16)),1,8) as bigint) ^ CAST(SUBSTRING(CAST(@guid2 as binary(16)),1,8) as bigint)
set @guid3_lo = CAST(SUBSTRING(CAST(@guid1 as binary(16)),9,8) as bigint) ^ CAST(SUBSTRING(CAST(@guid2 as binary(16)),9,8) as bigint)

set @guid3_temp = SUBSTRING(dbo.sp_hexadecimal(@guid3_hi), 3, 16) + SUBSTRING(dbo.sp_hexadecimal(@guid3_lo), 3, 16)
select @guid3_temp

set @guid3_char = SUBSTRING(@guid3_temp, 1, 8) + '-' + SUBSTRING(@guid3_temp, 9, 4) + '-' + SUBSTRING(@guid3_temp, 13, 4) + '-' + SUBSTRING(@guid3_temp, 17, 4) + '-' + SUBSTRING(@guid3_temp, 21, 12)
select @guid3_char

set @guid3 = convert(uniqueidentifier, @guid3_char)
select @guid3

--result 92CE4B69-58E1-5CB3-72AF-0117FB83ECD6

将二进制转换为十六进制字符串的函数来自:Converting Binary Data to Hexadecimal String

我知道在SQL 2008中我们可以使用convert函数来执行此操作,因为这篇文章解释过:SQL Server 2008 : new binary – hex string conversion,但在我的情况下这不是一个选项。

但是,如果有人更好地了解如何在二进制数据类型上使用SQL按位运算,那将会很好。

编辑:

感谢cyberkiwi提供正确的算法并指出我的代码中的错误。 此代码可能适用于XOR-ing二进制文件但不适用于GUID,因为GUID对于第一个和最后一个8字节具有不同的字节顺序。请查看维基百科的解释:GUID Basic structure。请注意,如果您要将XOR-ed结果用作真正的GUID,则应考虑版本位。

答案 3 :(得分:1)

我使用bigint来存储两个值。这样你就可以获得更多的射程。如果该值大于bigint,则可能需要将值拆分为两个bigint并使用AND / OR运算符组合。