Loop Through bitarray для извлечения подмножеств этого bitarray - PullRequest
0 голосов
/ 11 октября 2018

Обновление

Этот вопрос был перемещен в https://codereview.stackexchange.com/questions/205366/loop-through-bitarray-to-retrieve-subsets-of-that-bitarray.Я не удалил его, потому что на него уже был ответ.

Цель:

Я хочу просмотреть циклы по битам и сохранить подмножества этого битаррэя в таблице.

Контекст:

У меня есть bitarray с 48 элементами, где каждый элемент представляет один час.Я хочу оглянуться назад на 24 часа с начала второго дня и извлечь интервалы, в которых последний бит равен 1.

Мне удалось этого добиться, но я хочу знать, может ли кто-нибудь предложить лучшее решение :)

У меня есть таблица с именем [Numbers], содержащая 5000 строк, созданных по этой ссылке https://www.mssqltips.com/sqlservertip/4176/the-sql-server-numbers-table-explained--part-1/.

SCRIPT:

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

1 Ответ

0 голосов
/ 11 октября 2018
Значение

A 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;

В качестве альтернативы, если у вас есть таблица чисел со степенями двух, вы можете просто маскировать биты без рекурсии:

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;
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...