Comparando dois bitmasks em SQL para ver se algum dos bits corresponder
-
02-07-2019 - |
Pergunta
Existe uma maneira de comparar dois bitmasks em Transact-SQL para ver se algum dos bits combinar? Eu tenho uma tabela de usuário com uma máscara de bits para todos os papéis o usuário pertence, e eu gostaria de selecionar todos os usuários que têm qualquer dos papéis na bitmask fornecido. Então, usando os dados a seguir, um papel máscara de bits 6 (designer + programador) deve selecionar Dave, Charlie e Susan, mas não 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
Todas as idéias? Obrigado.
Solução
A resposta à sua pergunta é usar o &
Bitwise assim:
SELECT * FROM UserTable WHERE Roles & 6 != 0
O 6
pode ser trocado por qualquer combinação de seu bitfield onde você quiser verificar que qualquer usuário tem um ou mais desses bits. Ao tentar validar esta Eu costumo achar que é útil para escrever este fora escrita comum em binário. Sua tabela de usuário olha como este:
1 2 4
------------------
Dave 0 1 1
Charlie 0 1 0
Susan 0 0 1
Nick 1 0 0
Seu teste (6) é este
1 2 4
------------------
Test 0 1 1
Se passar por cada pessoa que faz a bitwaise e contra o teste obtemos estes:
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)
O acima deve demonstrar que os registros onde o resultado não é zero tem uma ou mais das bandeiras solicitados.
Edit: Aqui está o caso de teste você deve querer verificar este
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
Outras dicas
Use o Transact-SQL bit a bit operador AND "&" e comparar o resultado a zero. Ainda melhor, em vez de codificar as funções como bits de uma coluna de número inteiro, utilizar colunas booleanos, uma para cada função. Em seguida, sua consulta seria simplesmente desenhador e programador amigável. Se você espera que os papéis de mudar muito ao longo do tempo de vida de sua aplicação, em seguida, usar uma tabela de muitos-para-muitos para mapear a associação entre os usuários e seus papéis. Ambas as alternativas são mais portáteis do que confiar na existência do bit a bit E operador.
SELECT * FROM UserTable WHERE Roles & 6 > 0
* SELECT FROM tabela WHERE mask1 & mask2> 0
exemplo:
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 todos os programadores usar:
SELECT * FROM UserTable WHERE Roles & 2 = 2