纠正错误的'位'

时间:2014-01-15 19:49:53

标签: sql sql-server bit-manipulation

我正在尝试修复数据,其中一列在int列中存储了多个位标志。

发生了什么事情就行了,设置了错误的标志(6)所以我需要准备一个脚本来修复受影响的记录。

我尝试过执行一些查询来提取看似错误的数据,但这是基于假设的,我想知道是否有更聪明的方法。

一些事实:

  • 应该设置的位是8,但使用了6
  • 该栏目前最多可存储23位,以表示物业的开/关状态(有花园/有家具/是房屋/停车场等)
  • 有些记录受到影响,有些记录不受影响

考虑到6位无效,我是否可以根据这一事实将这些记录拉出来?

4 个答案:

答案 0 :(得分:1)

我假设你在这里谈论bit masking

有了这个假设,我认为您无法仅查询数据以获得修复。 bit masking的工作方式是将所有位的值相加(即将二进制转换为int),因此以下掩码:1001将存储为9

如果使用6而不是8,则将4和2位都设置为相同。因此,您的查询将返回4位和2位打开的所有有效记录。

使用相同的示例,如果您不小心使用了6而不是8,那么1001会变为7,但您如何区别于0111哪个会被正确屏蔽为7?

答案 1 :(得分:1)

请注意,在处理32位有符号值时,位31可能会出现问题。否则:

-- Check each bit in an integer.
declare @Sample as Int = 6;
with Bits as (
  select Cast( 1 as BigInt ) as BitMask, 0 as BitPosition
  union all
  select Bitmask * 2, BitPosition + 1
    from Bits
    where BitPosition < 31 )
  select BitPosition, BitMask,
    case when Cast( @Sample as BigInt ) & BitMask <> 0 then 'Set' else 'Clear' end as State
    from Bits;

-- Play with some sample data in a table.
declare @Samples as Table ( SampleId Int Identity, Number Int );
insert into @Samples ( Number ) values ( 0 ), ( 1 ), ( 2 ), ( 3 ), ( 30 ), ( 65 ), ( 16385 );
select * from @Samples;

-- Clear bit 6 in each row.
update @Samples
  set Number &= 2147483647 - Power( 2, 6 );
select * from @Samples;

-- Set bit 6 in each row.
update @Samples
  set Number |= Power( 2, 6 );
select * from @Samples;

-- Clear bit 6 in each row again.
update @Samples
  set Number &= 2147483647 - Power( 2, 6 );
select * from @Samples;

答案 2 :(得分:0)

您可以使用T-SQL bitwise operators完成此操作,如下所示:

set nocount on;

declare @test table (id int identity primary key, bits int);

insert into @test values(63);
insert into @test values(1);

select id, cast(bits as binary(4)) as 'bits' 
from @test;

update @test
set bits = (bits & 8388575) | 128
where (bits & 32) <> 0;

select id, cast(bits as binary(4)) as 'bits' 
from @test;

/*
Outputs

id          bits
----------- ----------
1           0x0000003F
2           0x00000001

id          bits
----------- ----------
1           0x0000009F
2           0x00000001

*/

答案 3 :(得分:0)

所以当你用6(二进制0110)掩盖时,你已经设置了第2位和第3位 - 好像你用4然后是2来掩盖。

所以你要做的就是检查那些设置的行。那些将是受影响的行 - 但是,其中一些可能已经设置了这些位。您将不得不手动完成,或以某种方式缩小数据集。也许将某些位组合设置无效?

此查询将为您提供已用6:

屏蔽的行列表
select * from table where bitfield & 6 = 6