4

技术情况:

给出的是SQL Server 2008 R2int中用于保存十进制“编码”位标志的列(范围从 2 0到 2 30,因此有 31 个可用标志,最大值为)。此列可能包含整个范围的可分配整数组合,全部用于对单个对象进行分类。1073741824

要解决的问题:

从有限数量的十进制“位整数”中,我们必须找到一个代表所有这些标志的某种交集的数字——比如当你有 时3,10,524290,很明显2应该在结果中设置,而其他位 ( 1,8,524288)是有争议的。这是一个非常基本的例子。这可能是一组真实的输入数据(仅前两列):

发生次数 | 十进制位域 | 二进制表示
     7 | 268435460 | 100000000000000000000000000100
     5 | 268435488 | 100000000000000000000000100000
     5 | 128 | 00000000000000000000010000000
     4 | 32 | 000000000000000000000000100000
     3 | 4 | 000000000000000000000000000100
     3 | 268435492 | 10000000000000000000000100100
     2 | 36 | 00000000000000000000000100100
     2 | 132 | 00000000000000000000010000100
     1 | 160 | 00000000000000000000010100000
   特定位的出现次数:3--------------------3-6--6--
     期望的输出可能性:10000000000000000000000100100

到目前为止的解决方案:

… 在 Transact-SQL 中实现:

  1. 收集所有要评估的整数并将它们连接成一个逗号分隔的字符串。
  2. 减少字符串,取出第一个数字,循环遍历:
  3. 对照最大值 ( &-AND) 检查受测者并将最大值除以 2 (while >=1)。

… 至今?Ò

现在我有一个二进制代表的比特集的输出。我考虑将这些位保存到一个 31 列的临时表中,以便进行评估。但后来我开始想:难道没有更聪明的方法可以做到这一点吗?SQL Server 速度超快,即使在反汇编 10000 个生成的整数时也是如此。但也许有一个内置函数可以计算两个二进制位标志之间的“距离”。

我承认这是一个复杂的问题,但我确实看到了隧道尽头的曙光,即使它需要以间接的方式完成。它会变得更加复杂,因为稍后还应该应用加权,因此 2׬ 00010000@ 100% 显着性>00010000@ 40% 显着性。但是,当我生成并可用的摘要时,我会尝试处理这个问题;-)

4

1 回答 1

1

您可以使用按位和进行操作

declare @i int
declare @x int
declare @cnt int
select @i=2147483647  -- 1111111 11111111 11111111 11111111
declare @t table (a int)
insert into @t values( 3),(10),(524290);

Select @i= (@i & a) from @t 


-- just for fun an output
set @x=1
set @cnt=0
While @cnt<31
  begin
  Print Case when @x & @i <> 0 then 'X' else ' ' end  +' ' + Cast(@x as Varchar(12))   
  Set @cnt=@cnt + 1
  if @cnt<31  Set @x=@x*2
  end 

或者更好的输出

declare @i int
declare @x int
declare @cnt int
select @i=2147483647  -- 1111111 11111111 11111111 11111111
Declare  @ref table(ref int) 
set @x=1
set @cnt=0
While @cnt<31
  begin
  insert into @ref Values(@x)
  Set @cnt=@cnt + 1
  if @cnt<31  Set @x=@x*2
  end 


declare @t table (a int)
insert into @t values( 3),(10),(524290);

Select @i= (@i & a) from @t 

Select * from @ref where ref&@i<>0 

作为对您评论的回答

declare @i int
declare @x int
declare @cnt int
select @i=2147483647  -- 1111111 11111111 11111111 11111111
Declare  @ref table(ref int) 
set @x=1
set @cnt=0
While @cnt<31
  begin
  insert into @ref Values(@x)
  Set @cnt=@cnt + 1
  if @cnt<31  Set @x=@x*2
  end 


declare @t table (a int)
insert into @t values( 3),(5),(9),(17),(33),(65),(128);

Select @i= (@i & a) from @t 

Select a,Count(*) as BitCount
from @ref r
join @t t on t.a & r.ref<>0
group by a

Select ref,Count(*) as OCC from @ref r
join @t t on t.a & r.ref<>0
group by ref

Select ref,(Select count(*) from @t where a & r.ref<>0) as OCC
from @ref r
于 2013-02-19T15:56:09.923 回答