2008-09-27 6 views
41

Czy istnieje sposób porównywania dwóch bitmask w języku Transact-SQL, aby sprawdzić, czy któryś z bitów jest zgodny? Mam tabelę użytkownika z maską bitową dla wszystkich ról, do których należy użytkownik, i chcę wybrać wszystkich użytkowników, którzy majądowolną liczbę ról w dostarczonej masce bitowej. Używając poniższych danych, rola maski bitowej 6 (projektant + programista) powinna wybrać Dave'a, Charliego i Susan, ale nie Nicka.Porównując dwie maski bitowe w SQL, aby sprawdzić, czy któryś z bitów pasuje do

User Table 
---------- 
ID Username Roles 
1 Dave  6 
2 Charlie 2 
3 Susan  4 
4 Nick  1 

Roles Table 
----------- 
ID Role 
1 Admin 
2 Programmer 
4 Designer

Jakieś pomysły? Dzięki.

Odpowiedz

61

Odpowiedź na to pytanie jest użyj Bitwise & w ten sposób:

SELECT * FROM UserTable WHERE Roles & 6 != 0 

Można wymienić 6 na dowolną kombinację swojego pola bitowego, w którym chcesz sprawdzić, czy każdy użytkownik ma jeden lub więcej z tych bitów. Podczas próby sprawdzenia poprawności, zazwyczaj pomocne jest zapisanie tego w formacie binarnym. Tabela użytkownik wygląda następująco:

 1 2 4 
------------------ 
Dave 0 1 1 
Charlie 0 1 0 
Susan 0 0 1 
Nick 1 0 0 

testu (6) jest to

 1 2 4 
------------------ 
Test 0 1 1 

Jeśli idziemy przez każdą osobę robi bitwaise i przeciwko testu otrzymujemy te:

 1 2 4 
------------------ 
Dave 0 1 1 
Test 0 1 1 
Result 0 1 1 (6) 

Charlie 0 1 0 
Test 0 1 1 
Result 0 1 0 (2) 

Susan 0 0 1 
Test 0 1 1 
Result 0 0 1 (4) 

Nick 1 0 0 
Test 0 1 1 
Result 0 0 0 (0) 

Powyższe powinno wykazać, że wszelkie zapisy, w których wynik nie jest zerowy, mają jedną lub więcej żądanych flag.

Edycja: Oto przypadek testowy powinien chcesz sprawdzić

with test (id, username, roles) 
AS 
(
    SELECT 1,'Dave',6 
    UNION SELECT 2,'Charlie',2 
    UNION SELECT 3,'Susan',4 
    UNION SELECT 4,'Nick',1 
) 
select * from test where (roles & 6) != 0 // returns dave, charlie & susan 

lub

select * from test where (roles & 2) != 0 // returns Dave & Charlie 

lub

select * from test where (roles & 7) != 0 // returns dave, charlie, susan & nick 
+0

Doskonale, dzięki. Zbyt dawno temu, aby pamiętać, jak w końcu udało mi się rozwiązać problem, ale to prawie na pewno lepsze rozwiązanie! – Nick

6

Użyj Transact-SQL bitwise AND operator "&" i porównaj wynik do zera. Co więcej, zamiast kodowania ról jako bitów w kolumnie całkowitej, należy użyć kolumn logicznych, po jednej dla każdej roli. Wtedy twoje zapytanie byłoby po prostu przyjazne dla projektanta i programisty. Jeśli spodziewasz się, że role ulegną dużej zmianie w całym okresie użytkowania aplikacji, użyj tabeli wiele do wielu w celu odwzorowania powiązania między użytkownikami i ich rolami. obie alternatywy są bardziej przenośne niż poleganie na istnieniu operatora bitowego-AND.

+0

Podręcznik & operator pracuje dla porównywania bitową z jednej roli, ale nie do porównywania maski bitowej z inną maską bitową. Myślę, że będę musiał użyć dynamicznego sql i umieścić każdą rolę w klauzuli where. – Nick

+1

@Nick - Wrong - zobacz moją odpowiedź. – Jamiec

0

znaleźć wszystkie programiści użyć:

SELECT * FROM UserTable WHERE Roles & 2 = 2 
+0

OP to lookign dla programistów LUB projektantów – ScottE

2

SELECT * FROM tabela WHERE mask1 & mask2> 0

2

przykład:

DECLARE @Mask int 
SET @Mask = 6 

DECLARE @Users TABLE 
(
ID int, 
Username varchar(50), 
Roles int 
) 

INSERT INTO @Users (ID, Username, Roles) 
SELECT 1, 'Dave', 6 
UNION 
SELECT 2, 'Charlie', 2 
UNION 
SELECT 3, 'Susan', 4 
UNION 
SELECT 4, 'Nick', 1 

SELECT * FROM @Users WHERE Roles & @Mask > 0 
+0

Daje to zły wynik.Spróbuj z 4 - Susan i Dave mają 4 - ale to tylko zwraca Susan. – Jamiec

+0

@Jamiec, tak, masz rację. Dzięki - naprawione. – ScottE

5
SELECT * FROM UserTable WHERE Roles & 6 > 0 
Powiązane problemy