Comparando dos máscaras de bits en SQL para ver si alguno de los bits coincide
-
02-07-2019 - |
Pregunta
¿Hay alguna forma de comparar dos máscaras de bits en Transact-SQL para ver si alguno de los bits coincide? Tengo una tabla de usuario con una máscara de bits para todas las funciones a las que pertenece el usuario, y me gustaría seleccionar a todos los usuarios que tengan cualquiera de las funciones en la máscara de bits suministrada. Entonces, usando los datos a continuación, una máscara de bits de roles de 6 (diseñador + programador) debe seleccionar a Dave, Charlie y Susan, pero no a 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
¿Alguna idea? Gracias.
Solución
La respuesta a su pregunta es usar el & amp;
de Bitwise de esta manera:
SELECT * FROM UserTable WHERE Roles & 6 != 0
El 6
puede intercambiarse por cualquier combinación de su campo de bits donde desee verificar que cualquier usuario tenga uno o más de esos bits. Cuando trato de validar esto, por lo general me resulta útil escribir esto a largo plazo en binario. Su tabla de usuario se ve así:
1 2 4
------------------
Dave 0 1 1
Charlie 0 1 0
Susan 0 0 1
Nick 1 0 0
Tu prueba (6) es esta
1 2 4
------------------
Test 0 1 1
Si pasamos por cada persona que hace el bitwise y contra la prueba obtenemos lo siguiente:
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)
Lo anterior debe demostrar que cualquier registro donde el resultado no sea cero tiene uno o más de los indicadores solicitados.
Editar: Este es el caso de prueba en caso de que quieras revisar esto
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
Otros consejos
Use el bitwise AND operator de Transact-SQL " & amp ; " y compara el resultado a cero. Aún mejor, en lugar de codificar los roles como bits de una columna entera, use columnas booleanas, una para cada rol. Entonces su consulta sería simplemente amigable con el diseñador y el programador. Si espera que los roles cambien mucho a lo largo de la vida útil de su aplicación, use una tabla de muchos a muchos para asignar la asociación entre los usuarios y sus roles. ambas alternativas son más portátiles que depender de la existencia del operador AND a nivel de bit.
SELECT * FROM UserTable WHERE Roles & 6 > 0
SELECCIONA * DESDE la tabla WHERE mask1 & amp; máscara2 > 0
ejemplo:
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
Para encontrar todos los programadores usa:
SELECT * FROM UserTable WHERE Roles & 2 = 2