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



就像在主题中一样,这里是问题摘要:我有大约480种不同的钢材。有些钢可以通过热和/或化学加工转化成另一种钢。此外,随着时间的推移,规范和技术发生了变化,一些突变变得不可能,而另一些则变得可行。我的生产环境需要能够自由和轻松地添加或删除单个钢类型,因为他们在数据库中搜索它们。

解决方案:我想使用位掩码来传递解决方案。每种型钢将被分配单独的有效钻头位置。可以放在一起的Steel类型可以将它们的位掩码组合在一起,创建默认的组搜索掩码。当用户在运行时修改组时,将在默认组搜索掩码中增加或减少单个钢类型的位掩码。当执行时,查询将对指定表中所有项的单个位掩码执行二进制and,并返回所有项,如searchMask & individualMask <> 0。我成功地将此原则用于其他应用程序,但SQL中的位操作符不能应用于一对二进制字段。我能使用的最大数据类型是64位bigint。

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

可以将掩码分割为64位块,分别检查每一对块,然后添加按位操作的结果,可以转换为函数的概念证明是

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中迭代较少。

最新更新