SQL Server的按位的行为很像C#枚举标志(SQL Server Bitwise behave

2019-07-04 07:21发布

我用的是旗上枚举在C#中,一切都很好,但希望使用类似的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#中,而不是在SQL Server中。

Answer 1:

在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


Answer 2:

虽然詹姆斯提出的位运算符将工作,它不会在关系数据库非常高性能的,尤其是当你尝试扩展到数百万的记录。 其原因是,在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会感谢你走这组面向路线。



Answer 3:

我几乎同样的问题,能想出这样的解决方案:

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


Answer 4:

C#枚举: CopEntry = 1 << 17

SQL服务器: case when (Features & power(2, 17)) = 0 then 0 else 1 end as COPEntry



文章来源: SQL Server Bitwise behave like C# Enum Flags