2012-11-30 40 views
16

我用的旗上枚舉在C#中,一切都很好,但要在以下情況下使用類似的東西在SQL:SQL Server的按位的行爲很像C#枚舉旗

我們要返回的用戶列表列表或條件,像這樣的一部分:

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中。

+4

這將是更「類似SQL的」存儲此信息在多對多表中。所以你應該把行(1,1),(1,2),(2,2),(3,1),(3,2),(3,3)'存儲在一個單獨的表中。它會使更自然的查詢,並提供索引機會。 –

回答

11

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 
14

雖然詹姆斯提出的位運算符將工作,它不會是很在關係數據庫中執行,尤其是當您嘗試擴展到數百萬條記錄時。原因是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會感謝您參加此集合導向的路線。

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