web-dev-qa-db-fra.com

Comparer deux masques de bits en SQL pour voir si l'un des bits correspond

Existe-t-il un moyen de comparer deux masques de bits dans Transact-SQL pour vérifier si l'un des bits correspond? J'ai une table utilisateur avec un masque de bits pour tous les rôles auxquels l'utilisateur appartient, et j'aimerais sélectionner tous les utilisateurs ayant aucun des rôles dans le masque de bits fourni. Donc, en utilisant les données ci-dessous, un masque de bits de rôles de 6 (concepteur + programmeur) devrait sélectionner Dave, Charlie et Susan, mais pas Nick.

Table utilisateur 
----------
ID Nom d'utilisateur Roles 
 1 Dave 6 
 2 Charlie 2 
 3 Susan 4 
 4 Nick 1 

Roles Table 
-----------
ID Rôle 
 1 Administrateur 
 2 Programmeur 
 4 Concepteur

Des idées? Merci.

44
Nick

La réponse à votre question consiste à utiliser le & au niveau du bit comme ceci:

SELECT * FROM UserTable WHERE Roles & 6 != 0

Le 6 peut être échangé contre n'importe quelle combinaison de votre champ binaire pour lequel vous souhaitez vérifier qu'un utilisateur possède un ou plusieurs de ces bits. Lorsque j'essaie de valider cela, je trouve généralement utile d'écrire cela en binaire. Votre table utilisateur ressemble à ceci:

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

Votre test (6) est-ce

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

Si nous examinons chaque personne en train de faire le bitwaise Et contre le test, nous obtenons ces:

        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) 

Ce qui précède doit démontrer que tous les enregistrements pour lesquels le résultat n'est pas nul ont un ou plusieurs des indicateurs demandés.

Edit: Voici le cas de test si vous voulez vérifier ceci

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

ou 

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

ou

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

Utilisez l'opérateur Transact-SQL et AND au niveau du bit "&" et comparez le résultat à zéro. Mieux encore, au lieu de coder les rôles sous forme de bits d'une colonne entière, utilisez des colonnes booléennes, une pour chaque rôle. Dans ce cas, votre requête sera simplement adaptée aux concepteurs ET aux programmeurs. Si vous vous attendez à ce que les rôles changent beaucoup au cours de la vie de votre application, utilisez un tableau plusieurs-pour-plusieurs pour mapper l'association entre les utilisateurs et leurs rôles. les deux alternatives sont plus portables que de s'appuyer sur l'existence de l'opérateur bitwise-AND.

6
Diomidis Spinellis
SELECT * FROM UserTable WHERE Roles & 6 > 0
5
Ben

exemple:

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
2
ScottE

SELECT * FROM table WHERE masque1 & masque2> 0

2
vsevik

Pour trouver tous les programmeurs, utilisez:

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