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.

È stato utile?

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
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top