该问题已移至https://codereview.stackexchange.com/questions/205366/loop-through-bitarray-to-retrieve-subsets-of-that-bitarray。我没有删除它,因为它已经有了答案。
我想遍历位数组并将该位数组的子集存储在表中。
我有一个包含48个元素的位数组,其中每个元素代表一个小时。我想从第二天开始24小时回顾一下,并检索最后一位为1的间隔。
我能够实现这一目标,但想知道是否有人可以提供更好的解决方案:)
我有一个名为[Numbers]的表,该表具有根据此链接https://www.mssqltips.com/sqlservertip/4176/the-sql-server-numbers-table-explained--part-1/创建的5000行。
DECLARE @Ba NVARCHAR(48) = '000011110000000001110000000011111111000011110000'
DECLARE @numberOfIntervals INT = 24;
DECLARE @intervals TABLE(
SequenceId INT,
[Periods] NVARCHAR(24)
)
INSERT INTO @intervals
SELECT number-1 AS [SequenceId], SUBSTRING(@Ba, number, @numberOfIntervals) AS [Values]
FROM [dbo].[Numbers]
WHERE number > 1 AND number <= (LEN(@Ba)-(@numberOfIntervals-1)) AND RIGHT(SUBSTRING(@Ba, number, @numberOfIntervals), 1) = '1'
SELECT * FROM @intervals
[SequenceId] [Values]
_________________________
5 111000000000111000000001
6 110000000001110000000011
7 100000000011100000000111
8 000000000111000000001111
9 000000001110000000011111
10 000000011100000000111111
11 000000111000000001111111
12 000001110000000011111111
17 111000000001111111100001
18 110000000011111111000011
19 100000000111111110000111
20 000000001111111100001111
答案 0 :(得分:1)
BigInt
值可以容纳64位。使用整数除法和按位运算符,您可以摆弄位。以下代码演示了从值中选择最低有效位,右移和重复。将where LSB = 1
添加到最后的select
将会滤除偶数。
declare @Foo as BigInt = 0x0F00700FF0F0; -- '0000 1111 0000 0000 0111 0000 0000 1111 1111 0000 1111 0000'
select @Foo as Foo, Cast( @Foo as VarBinary(6) ) as FooHex;
with ShiftedBits as (
-- Start with the original value and pick off the least-significant-bit.
select @Foo as Foo, 0 as Position, @Foo & 1 as LSB
union all
-- Right shift the value and repeat.
select Foo / 2, Position + 1, Foo / 2 & 1
from ShiftedBits
where Position < 47 )
-- Display the value, position and bit.
select Foo, Cast( Foo as VarBinary(6) ) as FooHex, Position, LSB
from ShiftedBits
order by Position;
或者,如果您具有2的幂数表,则可以简单地掩盖位,而无需递归:
declare @Foo as BigInt = 0x0F00700FF0F0; -- '0000 1111 0000 0000 0111 0000 0000 1111 1111 0000 1111 0000'
select @Foo as Foo, Cast( @Foo as VarBinary(6) ) as FooHex;
-- Create a powers-of-two table.
declare @PowersOfTwo as Table ( P Int, P2 BigInt );
with PowersOfTwo as (
select 0 as P, Cast( 1 as BigInt ) as P2
union all
select P + 1, P2 * 2
from PowersOfTwo
where P < 47 )
insert into @PowersOfTwo
select P, P2
from PowersOfTwo;
select *, Cast( P2 as VarBinary(6) ) as P2Hex from @PowersOfTwo order by P;
-- Pick the bits.
select P, P2, Cast( P2 as VarBinary(6) ) as P2Hex,
Cast( @Foo & P2 as VarBinary(6) ) as MaskedBit,
Cast( @Foo / P2 as VarBinary(6) ) as ShiftedValue,
case when @Foo & P2 = 0 then 'bad' else 'good' end as Keeper
from @PowersOfTwo;