According this link: Bitwise Operators (Transact-SQL) we can do bitwise operation between binary and int, smallint, tinyint or vice versa.
But how can I make a bitwise exclusive OR in sql server between two binary types? Or if this is not possible how can I split a binary/varbinary to individual by开发者_如何学运维tes?
The reason I'm asking for this is because I need to xor two numbers bigger than max int value. Thanks.
All comments in code block
-- 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)))
Per the Bitwise Exclusive OR documentation:
Note
Only one expression can be of either binary or varbinary data type in a bitwise operation.
The comment in the question from Martin, gave me an idea how to split binary so I can XOR the values. Originally I wanted to XOR two GUIDs in sql. So here is the code I came with:
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
The function to convert binary to hex string is from: Converting Binary Data to Hexadecimal String
I know that in SQL 2008 we can use convert function to do this as this post explained: SQL Server 2008 : new binary – hex string conversion, but this was not an option in my case.
However it will be good if someone has a better idea how we can use SQL bitwise operations on binary data type.
EDIT:
Thanks to cyberkiwi for providing the correct algorithm and for point the error in my code. This code could be good for XOR-ing binary but not for GUIDs, as GUIDs have different byte order for first and last 8 bytes. Please look at the wikipedia explanation for this: GUID Basic structure. Note that if you are going to use the XOR-ed result as real GUID you should take and into account the version bits.
I used bigints for storing both values. This way you'll get more range. If the value is bigger than bigint, you might need to split the values in two bigint and use AND / OR operator combination.
精彩评论