如何对长二进制值(超过64位)执行二进制comp

时间:2014-07-11 16:48:46

标签: sql sql-server tsql bit-manipulation

喜欢这个主题,这里是问题简介: 我有480种不同的钢种。一些钢可以通过加热和/或化学处理转化为另一种钢。此外,多年来规范和技术发生变化,一些突变变得不可能,其他突变变得可用。我的生产环境需要在db中搜索它们时自由而轻松地添加或删除单个钢种。

解决方案:我想使用位掩码来提供解决方案。每种钢种都将分配单独的有效钻头位置。可以组合在一起的钢类型将其位掩码组合在一起,创建默认的组搜索掩码。当使用在运行时修改组时,将从默认组搜索掩码中添加或减去单个钢类型的位掩码。执行时,查询将针对指定表中所有项的各个位掩码执行二进制AND运算并返回所有类似searchMask & individualMask <> 0我成功将此原则用于其他应用程序但SQL中的位运算符不能应用于一对二进制字段。我可以使用的最大数据类型是64位bigint。

因此,问题是,如何在T-SQL中对两个二进制字段执行二进制AND运算,或者我可以使用哪些其他解决方案来解决上述问题而不创建任意组?

1 个答案:

答案 0 :(得分:1)

一个想法可以是将掩码分成64位的块并分别检查每一个chunck然后添加按位运算的结果,可以转换为函数的概念证明

DECLARE @a VARBINARY(200) = Cast(Replicate(Char(128), 200) AS VARBINARY(200)) 
DECLARE @b VARBINARY(200) = Cast(Replicate(Char(130), 200) AS VARBINARY(200)); 

WITH splitter AS (
  SELECT Cast(Cast(LEFT(@a, 64) AS VARBINARY(64)) AS BIGINT) a
       , Cast(Cast(LEFT(@b, 64) AS VARBINARY(64)) AS BIGINT) b 
       , _and = Cast(0 AS BIT)
       , b = 1
       , rev = Cast(Ceiling(Len(@a) / 64.0) AS INT) 
  UNION ALL 
  SELECT Cast(Cast(Substring(@a, b * 64, 64) AS VARBINARY(64)) AS BIGINT) a
       , Cast(Cast(Substring(@b, b * 64, 64) AS VARBINARY(64)) AS BIGINT) b 
       , _and = _and | Cast(a & b AS BIT), 
       , b = b + 1, 
       , rev = rev - 1 
  FROM   splitter 
  WHERE  b * 64 < Len(@a)
) 
SELECT _and | Cast(a & b AS BIT) 
FROM   splitter 
WHERE  rev = 1 

递归CTE,有很多CAST,每64字节生成一行,并按位AND执行前两个块,CASTBIT要确保可以在类型空间中添加值,使用按位OR,因为BIT无法求和。

代码假设两个值具有相同的维度,如果相反,则@a应该是较短的值,以便在递归CTE中具有较少的迭代。