James によって提案されたビット単位の演算子は機能しますが、特に数百万のレコードにスケーリングしようとする場合、リレーショナル データベースではあまりパフォーマンスが高くありません。その理由は、where 句の関数がサージ可能ではない(インデックス シークを防止する) ためです。
私がすることは、フラグと条件の可能なすべての組み合わせを含むテーブルを作成することです。これにより、条件でのインデックスシークが可能になります。
FlagConditions を入力します。シングル(tinyint)を使用しました。さらにフラグが必要な場合は、このアプローチを拡張できるはずです。
CREATE TABLE FlagConditions (
Flag TINYINT
, Condition TINYINT
, CONSTRAINT Flag_Condition PRIMARY KEY CLUSTERED (Condition,Flag)
);
CREATE TABLE #Flags (
Flag TINYINT IDENTITY(0,1) PRIMARY KEY CLUSTERED
, DummyColumn BIT NULL);
GO
INSERT #Flags
( DummyColumn )
SELECT NULL;
GO 256
CREATE TABLE #Conditions(Condition TINYINT PRIMARY KEY CLUSTERED);
INSERT #Conditions ( Condition )
VALUES (1),(2),(4),(8),(16),(32),(64),(128);
INSERT FlagConditions ( Flag, Condition )
SELECT
Flag, Flag & Condition
FROM #Flags f
CROSS JOIN #Conditions c
WHERE Flag & Condition <> 0;
DROP TABLE #Flags;
DROP TABLE #Conditions;
列挙型のビット単位の条件を効率的にシークする必要があるときはいつでも、FlagConditions テーブルを使用できるようになりました。
DECLARE @UserFlags TABLE (Username varchar(10), Flag tinyint);
INSERT @UserFlags(Username, Flag)
VALUES ('User1',6),('User2',4),('User3',14);
DECLARE @Condition TINYINT = 2;
SELECT u.*
FROM @UserFlags u
INNER JOIN FlagConditions fc ON u.Flag = fc.Flag
WHERE fc.Condition = @Condition;
これは以下を返します:
Username Flag
---------- ----
User1 6
User3 14
あなたの DBA は、このセット指向のルートに進んでくれたことに感謝するでしょう。