设置第 32 位和第 64 位很棘手。
32位解决方案:
我让它适用于 32 位字段。诀窍是在将 POWER 函数的返回值转换为 int 之前将其转换为 binary(4)。如果您尝试直接转换为 int,而不先转换为 binary(4),则在对第 32 位(索引 31)进行操作时会出现算术溢出异常。此外,您必须确保传递给 POWER 的表达式具有足够大的类型(例如 bigint)以存储最大返回值 (2^31),否则 POWER 函数将引发算术溢出异常。
CREATE FUNCTION [dbo].[SetIntBit]
(
@bitfieldvalue int,
@bitindex int, --(0 to 31)
@bit bit --(0 or 1)
)
RETURNS int
AS
BEGIN
DECLARE @bitmask int = CAST(CAST(POWER(CAST(2 as bigint),@bitindex) as binary(4)) as int);
RETURN
CASE
WHEN @bit = 1 THEN (@bitfieldvalue | @bitmask)
WHEN @bit = 0 THEN (@bitfieldvalue & ~@bitmask)
ELSE @bitfieldvalue --NO CHANGE
END
END
64位问题:
我打算对 64 位字段使用类似的方法,但是我发现 POWER 函数返回的值不准确,尽管表达式/返回值使用了 decimal(38) 类型。例如:“select POWER(CAST(2 as decimal(38)), 64)”返回 18446744073709552000(只有前 16 位数字是准确的)而不是 18446744073709551616 的正确值。即使我只将 2 提高到63次方,那个结果还是不准确的。
POWER 函数的文档表明“如果使用货币或数字数据类型,则内部转换为浮点数会导致精度损失。” (注意数字类型在功能上等同于十进制类型)。
我认为正确处理 64 位字段的唯一方法是对它们的 32 位一半进行操作,但这需要对 @bitindex 属性进行额外检查,以查看我需要对哪一半进行操作。是否有任何内置函数或更好的方法来显式设置 TSQL 中 32 位和 64 位位掩码字段中的最终位?