Confronto tra due maschere di bit in SQL per vedere se uno dei bit corrisponde
-
02-07-2019 - |
Domanda
Esiste un modo per confrontare due maschere di bit in Transact-SQL per vedere se qualcuno dei bit corrisponde? Ho una tabella Utente con una maschera di bit per tutti i ruoli a cui appartiene l'utente e vorrei selezionare tutti gli utenti che hanno qualsiasi dei ruoli nella maschera di bit fornita. Quindi, utilizzando i dati di seguito, una maschera di bit di ruoli di 6 (designer + programmatore) dovrebbe selezionare Dave, Charlie e Susan, ma non Nick.
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
Qualche idea? Grazie.
Soluzione
La risposta alla tua domanda è di usare Bitwise & amp;
in questo modo:
SELECT * FROM UserTable WHERE Roles & 6 != 0
Il 6
può essere scambiato con qualsiasi combinazione del tuo bitfield in cui desideri verificare che qualsiasi utente abbia uno o più di quei bit. Quando provo a convalidare questo, di solito trovo utile scrivere a mano in binario. La tabella utenti è simile alla seguente:
1 2 4
------------------
Dave 0 1 1
Charlie 0 1 0
Susan 0 0 1
Nick 1 0 0
Il tuo test (6) è questo
1 2 4
------------------
Test 0 1 1
Se passiamo attraverso ogni persona che fa il bitwaise E contro il test otteniamo questi:
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)
Quanto sopra dovrebbe dimostrare che tutti i record in cui il risultato non è zero ha uno o più dei flag richiesti.
Modifica: ecco il caso di prova se vuoi verificarlo
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
o
select * from test where (roles & 2) != 0 // returns Dave & Charlie
o
select * from test where (roles & 7) != 0 // returns dave, charlie, susan & nick
Altri suggerimenti
Utilizza Transact-SQL bitwise AND operator " & amp; ; " e confronta il risultato con zero. Ancora meglio, invece di codificare i ruoli come bit di una colonna intera, usa colonne booleane, una per ogni ruolo. Quindi la tua query sarebbe semplicemente adatta a progettisti e programmatori. Se ti aspetti che i ruoli cambino molto nel corso della vita della tua applicazione, usa una tabella molti-a-molti per mappare l'associazione tra utenti e loro ruoli. entrambe le alternative sono più portabili che affidarsi all'esistenza dell'operatore AND bit a bit.
SELECT * FROM UserTable WHERE Roles & 6 > 0
SELEZIONA * DA tabella DOVE maschera1 & amp; mask2 > 0
Esempio:
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
Per trovare tutti i programmatori usare:
SELECT * FROM UserTable WHERE Roles & 2 = 2