使用 T-SQL 在 BIGINT 中间提取位移后的数字
Extracting bit-shifted numbers in the middle of a BIGINT with T-SQL
一位同事想出了一个内部 ID,它结合了多个不同的标识符,所有标识符都移位在一起。
我正在尝试使用 T-SQL 从这个 BIGINT
中取出 "TotalSeconds"。我能想到的唯一方法是对位 21(?) 到 50 的数字执行 AND,然后将其转换回 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)
注意:SQL服务器无法正常处理无符号整数。
除以2的幂相当于右移,例如Foo >> 3
在 C# 中将是 Foo / Power( 2, 3 )
在 TSQL 中。它适用于最多 64 位的整数类型。
按位与 (&
) and modulus (%
) 可以与 2 的幂一起使用,但它们不可互换。要提取五个最低有效位,您可以使用 Foo % Power( 2, 5 )
或 Foo & ( Power( 2, 5 ) - 1 )
。第一个 returns 除以 0x20 后的余数,第二个使用掩码 0x1F 屏蔽不需要的位。有两个重要区别需要牢记:(1) 按位 AND 仅限于 32 位值,而模数最多适用于 64 位,并且 (2) 如果原始值为负,则结果的符号不同:
select 10 % 4 as ModPos, 10 & 3 as AndPos, -10 % 4 as ModNeg, -10 & 3 as AndNeg;
把它们放在一起,你可以从 BigInt
值的 LSB 中提取一个 FieldWidth
位开始 FieldOffset
位的位域,方法是将原始值除以移动对最低有效位感兴趣,然后屏蔽掉任何不需要的位:
( OriginalValue / Power( 2, FieldOffset) ) % Power( 2, FieldWidth )
原始问题涉及将结果 NumberOfSeconds
转换为 TimeSpan
。最接近的 TSQL 数据类型是 Time
并且它被限制为小于 24 小时的值,即一天中的时间。如果该值在Time
范围内,则可以这样转换:
Cast( DateAdd( second, NumberOfSeconds, 0 ) as Time )
一位同事想出了一个内部 ID,它结合了多个不同的标识符,所有标识符都移位在一起。
我正在尝试使用 T-SQL 从这个 BIGINT
中取出 "TotalSeconds"。我能想到的唯一方法是对位 21(?) 到 50 的数字执行 AND,然后将其转换回 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)
注意:SQL服务器无法正常处理无符号整数。
除以2的幂相当于右移,例如Foo >> 3
在 C# 中将是 Foo / Power( 2, 3 )
在 TSQL 中。它适用于最多 64 位的整数类型。
按位与 (&
) and modulus (%
) 可以与 2 的幂一起使用,但它们不可互换。要提取五个最低有效位,您可以使用 Foo % Power( 2, 5 )
或 Foo & ( Power( 2, 5 ) - 1 )
。第一个 returns 除以 0x20 后的余数,第二个使用掩码 0x1F 屏蔽不需要的位。有两个重要区别需要牢记:(1) 按位 AND 仅限于 32 位值,而模数最多适用于 64 位,并且 (2) 如果原始值为负,则结果的符号不同:
select 10 % 4 as ModPos, 10 & 3 as AndPos, -10 % 4 as ModNeg, -10 & 3 as AndNeg;
把它们放在一起,你可以从 BigInt
值的 LSB 中提取一个 FieldWidth
位开始 FieldOffset
位的位域,方法是将原始值除以移动对最低有效位感兴趣,然后屏蔽掉任何不需要的位:
( OriginalValue / Power( 2, FieldOffset) ) % Power( 2, FieldWidth )
原始问题涉及将结果 NumberOfSeconds
转换为 TimeSpan
。最接近的 TSQL 数据类型是 Time
并且它被限制为小于 24 小时的值,即一天中的时间。如果该值在Time
范围内,则可以这样转换:
Cast( DateAdd( second, NumberOfSeconds, 0 ) as Time )