如何在SQL中的两个varbinary字段之间执行AND BIT OPERATOR

时间:2015-03-30 03:13:38

标签: sql sql-server sql-server-2012

有人可以建议这种方法的良好解决方案。

我有2个长度为1024位的二进制字符串(1010101 ....)

现在我想对两者进行位操作(AND)以得到一个值是否大于0。

目前我正在将字符串转换为十六进制(256)和varbinary(128)

所以,一旦我有两个varbinary,我将每个字节转换为BIGINT,并在两个BIG INT上进行AND。

任何人都可以在SQL 2012中建议我更好的方法。

谢谢, 巴拉

3 个答案:

答案 0 :(得分:1)

经过长时间的讨论,我终于找到了你的输入数据。你有一个varbinary(128),由一个长度为1024个字符的二进制字符串(如'1000010010101 ...')构成。 SQL Server不提供执行此类转换的就绪函数。我已经建了一个让我测试。以下函数执行此类转换:

CREATE FUNCTION dbo.binStringToBinary(@inputString VARCHAR(1024)) RETURNS VARBINARY(128) AS
BEGIN
    DECLARE @inputBinary VARBINARY(128) = convert(varbinary, '', 2)
    DECLARE @octet int = 1
    DECLARE @len int
    SET @len = Len(@inputString)
    while @octet < @len
    BEGIN
        DECLARE @i int = 0
        DECLARE @Output int = 0
        WHILE(@i < 7) BEGIN
            SET @Output = @Output + POWER(CAST(SUBSTRING(@inputString, @octet + @i, 1) AS int) * 2, 7 - @i)
            SET @i = @i + 1
        END
        SET @Output = @Output + CAST(SUBSTRING(@inputString, @octet + @i, 1) AS int)
        select @inputBinary = @inputBinary + convert(varbinary(1), @Output)
        -- PRINT substring(@inputString, @octet, 8) + ' ' + STR(@Output, 3, 0) + ' ' + convert(varchar(1024), @inputBinary, 2)
        SET @octet = @octet + 8
    END
    RETURN @inputBinary
END

然后我编写了一个函数,使用varbinary(128)作为输入来检查一点:

CREATE FUNCTION dbo.[DoBitsMatchFromBinary](@bitToCheck INT,@inputBinary VARBINARY(1024))
RETURNS BIT
AS
BEGIN
    IF @bitToCheck < 1 OR @bitToCheck > 1024
        RETURN 0

    DECLARE @byte int = (@bitToCheck - 1) / 8
    DECLARE @bit int = @bitToCheck - @byte * 8
    DECLARE @bytemask int = POWER(2, 8-@bit)
    SET @byte = @byte + 1

    RETURN CASE WHEN CONVERT(int, CONVERT(binary(1), SUBSTRING(@inputBinary, @byte, 1), 2)) & @bytemask = @bytemask THEN 1 ELSE 0 END
END

作为奖励,我还在这里包含了一个从输入二进制字符串(1024)进行位检查的函数:

CREATE FUNCTION dbo.[DoBitsMatchFromBinString](@bitToCheck INT,@inputString VARCHAR(1024))
RETURNS BIT
AS
BEGIN
    IF @bitToCheck < 1 OR @bitToCheck > 1024
        RETURN 0

    RETURN CASE WHEN SUBSTRING(@inputString, @bitToCheck, 1) = '1' THEN 1 ELSE 0 END
END

查看演示其用法的SQL fiddle

DECLARE @inputBinary VARBINARY(128)
select @inputBinary = dbo.binStringToBinary('1010001000101111010111010100001101000100010111101011101010000101101000100010111101011101010000110100010001011110101110101000010110100010001011110101110101000011010001000101111010111010100001011010001000101111010111010100001101000100010111101011101010000101101000100010111101011101010000110100010001011110101110101000010110100010001011110101110101000011010001000101111010111010100001011010001000101111010111010100001101000100010111101011101010000101101000100010111101011101010000110100010001011110101110101000010110100010001011110101110101000011010001000101111010111010100001011010001000101111010111010100001101000100010111101011101010000101101000100010111101011101010000110100010001011110101110101000010110100010001011110101110101000011010001000101111010111010100001011010001000101111010111010100001101000100010111101011101010000101101000100010111101011101010000110100010001011110101110101000010110100010001011110101110101000011010001000101111010111010100001011010001000101111010111010100001101000100010111101011101010000101')
select dbo.[DoBitsMatchFromBinary](1, @inputBinary) bit1,
       dbo.[DoBitsMatchFromBinary](2, @inputBinary) bit2,
       dbo.[DoBitsMatchFromBinary](3, @inputBinary) bit3,
       dbo.[DoBitsMatchFromBinary](4, @inputBinary) bit4,
       dbo.[DoBitsMatchFromBinary](5, @inputBinary) bit5,
       dbo.[DoBitsMatchFromBinary](6, @inputBinary) bit6,
       dbo.[DoBitsMatchFromBinary](7, @inputBinary) bit7,
       dbo.[DoBitsMatchFromBinary](8, @inputBinary) bit8,
       dbo.[DoBitsMatchFromBinary](1017, @inputBinary) bit1017,
       dbo.[DoBitsMatchFromBinary](1018, @inputBinary) bit1018,
       dbo.[DoBitsMatchFromBinary](1019, @inputBinary) bit1019,
       dbo.[DoBitsMatchFromBinary](1020, @inputBinary) bit1020,
       dbo.[DoBitsMatchFromBinary](1021, @inputBinary) bit1021,
       dbo.[DoBitsMatchFromBinary](1022, @inputBinary) bit1022,
       dbo.[DoBitsMatchFromBinary](1023, @inputBinary) bit1023,
       dbo.[DoBitsMatchFromBinary](1024, @inputBinary) bit1024


| bit1 |  bit2 | bit3 |  bit4 |  bit5 |  bit6 | bit7 |  bit8 | bit1017 | bit1018 | bit1019 | bit1020 | bit1021 | bit1022 | bit1023 | bit1024 |
|------|-------|------|-------|-------|-------|------|-------|---------|---------|---------|---------|---------|---------|---------|---------|
| true | false | true | false | false | false | true | false |    true |   false |   false |   false |   false |    true |   false |    true |

答案 1 :(得分:1)

使用numbers table分割字符串。使用intersect进行比较并检查是否有任何行。

declare @s1 char(1024) = '01100100001',
        @s2 char(1024) = '00000100001';

if exists (
          select substring(@s1, N.Number, 1) as C,
                N.Number
          from Numbers as N
          where N.Number between 1 and 1024 and
                substring(@s1, N.Number, 1) = '1'
          intersect
          select substring(@s2, N.Number, 1) as C,
                N.Number
          from Numbers as N
          where N.Number between 1 and 1024 and
                substring(@s2, N.Number, 1) = '1'
          )
begin
  select 'YES'
end
else
begin
  select 'NO'
end;

您获得的查询计划非常有效,并且在您匹配时会提前终止:

enter image description here

顶部聚集索引搜索将扫描数字表格从1到1024,并使用残差谓词检查@s1每个位置是否有1。对于发现的每个1,它会在对数字表的另一个引用中进行搜索,以查看1中该位置是否还有@s2。找到匹配后,执行将停止。

答案 2 :(得分:1)

  

如果你的二进制数字可以转换为任何数字类型,这个答案可以帮助你。

<强>&安培; (按位AND)(Transact-SQL)
在两个整数值之间执行按位逻辑AND运算。

expression & expression

<强>表达
是整数数据类型类别,位或二进制或varbinary数据类型的任何数据类型的任何有效表达式。表达式被视为按位运算的二进制数。

  

注意:
  在按位运算中,只有一个表达式可以是二进制或varbinary数据类型。

...
如果可能,您可以将其中一个表达式转换为类似bigint的类型。

declare @b1 varbinary(max) = 0x2, @b2 varbinary(max) = 0x3

print Cast(@b1 & cast(@b2 as bigint) as varbinary(max))

结果是:

0x0000000000000002