我在C#中的枚举上使用了Flags,一切都很好但是想在以下场景中使用类似SQL的东西:
我们希望返回属于列表或类似条件的用户列表:
ConditionOne = 2
ConditionTwo = 4
ConditionThree = 8
等...
我们会让用户遇到以下某些情况:
User1: 6 (conditions 1 and 2)
User2: 4 (condition 2)
User3: 14 (conditions 1, 2 and 3)
等...
我们希望能够进行查询,我们说所有用户都获得条件1,在这种情况下,即使他们还有其他条件,它也会返回用户1和3。
非常感谢任何见解,只在C#中使用Flags,而不是直接在Sql Server中使用。
答案 0 :(得分:22)
SQL中的按位运算符是&
。 WHERE
子句需要求值为BOOLEAN
表达式,如下所示:
create table #temp (id int, username varchar(20), flags int)
insert into #temp values
(1, 'User1', 6),
(2, 'User2', 4),
(3, 'User3', 14)
declare @ConditionOne int = 2
select *
from #temp
where flags & @ConditionOne <> 0
drop table #temp
此查询返回以下数据集:
id username flags
----------- -------------------- -----------
1 User1 6
3 User3 14
答案 1 :(得分:18)
虽然James建议的按位运算符可以工作,但它在关系数据库中不会非常高效,尤其是当您尝试扩展到数百万条记录时。原因是where子句中的函数不是sargable(它们阻止索引查找)。
我要做的是创建一个包含所有可能的标志和条件组合的表,这将启用索引查找条件。
填充FlagConditions。我用了一个(tinyint)。如果您需要更多Flags,您应该能够扩展这种方法:
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;
现在,只要您需要有效地搜索enum按位条件,就可以使用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会感谢你走这条面向集合的路线。
答案 2 :(得分:5)
我遇到了几乎相同的问题,可以提出这样的解决方案:
SELECT t.value
, ISNULL(t.C1 + ', ', '') + ISNULL(t.C2, '') + ISNULL(', ' + t.C3, '') AS [type]
FROM
(
SELECT value,
CASE WHEN (type & 2) <> 0 THEN 'Type1' END AS C1,
CASE WHEN (type & 4) <> 0 THEN 'Type2' END AS C2,
CASE WHEN (type & 8) <> 0 THEN 'Type3' END AS C3
FROM db.Agent
) t
结果如下:
value type
---------- ------------------------------------
14 Type1, Type2, Type3
12 Type2, Type3
14 Type1, Type2, Type3
答案 3 :(得分:0)
C#枚举:CopEntry = 1 << 17
SQL Server:case when (Features & power(2, 17)) = 0 then 0 else 1 end as COPEntry