Извлечение сдвинутых битов чисел в середине BIGINT с T- SQL - PullRequest
0 голосов
/ 26 февраля 2020

Сотрудник придумал внутренний идентификатор, который объединяет несколько разных идентификаторов, причем все битовые смещения.

Я пытаюсь получить "TotalSeconds" из этого BIGINT, используя T- SQL. Единственный способ, который я могу придумать, это сделать вместо числа, которое будет биты от 21 (?) До 50, и преобразовать его обратно в INT, а затем использовать dateadd, чтобы получить время.

В частности, эта часть:

StartUTC = new DateTime(BaseYear, 1, 1).ToUniversalTime();
TimeSpan timeSpan = DateTime.UtcNow - StartUTC;
...(one of the identifiers)
+ (((ulong) timeSpan.TotalSeconds % 1073741824L) << 20) + // 30 bits.
...(another of the identifiers)

1 Ответ

1 голос
/ 27 февраля 2020

Примечание: SQL Сервер не справляется с беззнаковыми целыми числами.

Деление на степень два эквивалентно сдвигу вправо, например, Foo >> 3 в C# будет Foo / Power( 2, 3 ) в Т SQL. Он работает с целочисленными типами до 64 бит.

Побитовое И (&) и модуль (%) могут использоваться с степенями два , но они не являются взаимозаменяемыми. Чтобы извлечь пять младших битов, вы можете использовать Foo % Power( 2, 5 ) или Foo & ( Power( 2, 5 ) - 1 ). Первый возвращает остаток после деления на 0x20, а второй маскирует нежелательные биты, используя маску 0x1F. Следует помнить о двух важных различиях: (1) побитовое И ограничено 32-битными значениями, в то время как модуль работает до 64-битных значений, и (2) если исходное значение является отрицательным, то знаки результатов отличаются:

select 10 % 4 as ModPos, 10 & 3 as AndPos, -10 % 4 as ModNeg, -10 & 3 as AndNeg;

Собрав все это вместе, вы можете извлечь битовое поле из FieldWidth бит, начиная с FieldOffset бит, из младшего бита значения BigInt путем деления исходного значения, чтобы переместить интересующие биты наименьшее значимые биты, а затем маскирование любых нежелательных битов:

( OriginalValue / Power( 2, FieldOffset) ) % Power( 2, FieldWidth )

Первоначальный вопрос заключается в преобразовании результирующего NumberOfSeconds в TimeSpan. Ближайший тип данных T SQL равен Time и ограничен значениями менее 24 часов, т. Е. Временем суток. Если значение находится в диапазоне Time, вы можете преобразовать его таким образом:

Cast( DateAdd( second, NumberOfSeconds, 0 ) as Time )
...