32番目と64番目のビットの設定には注意が必要です。
32ビットソリューション:
32ビットフィールドで動作するようになりました。秘訣は、POWER関数の戻り値をintにキャストする前にbinary(4)にキャストすることです。最初にbinary(4)にキャストせずに、intに直接キャストしようとすると、32番目のビット(インデックス31)で操作するときに算術オーバーフロー例外が発生します。また、POWERに渡される式が、最大戻り値(2 ^ 31)を格納するのに十分な大きさの型(bigintなど)であることを確認する必要があります。そうしないと、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ビットフィールドにも同様のアプローチを使用するつもりでしたが、式/戻り値にdecimal(38)タイプを使用しているにもかかわらず、POWER関数が不正確な値を返していることがわかりました。例: "select POWER(CAST(2 as decimal(38))、64)"は、正しい値18446744073709551616ではなく、18446744073709552000(最初の16桁のみが正確)を返します。 63乗、その結果はまだ不正確です。
POWER関数のドキュメントには、「お金または数値データ型のいずれかが使用されている場合、floatへの内部変換によって精度が低下する可能性がある」と記載されています。(数値型は機能的に10進数型と同等であることに注意してください)。
64ビットフィールドを適切に処理する唯一の方法は、32ビットの半分を操作することだと思いますが、これには、@ bitindexプロパティを追加でチェックして、どちらの半分を操作する必要があるかを確認する必要があります。TSQLの32ビットおよび64ビットビットマスクフィールドにこれらの最終ビットを明示的に設定するための組み込み関数またはより良い方法はありますか?