Подтвердить что ты не робот

Сравнение двух битовых масок в SQL, чтобы узнать, соответствует ли какой-либо бит

Есть ли способ сравнения двух битмасков в Transact-SQL, чтобы узнать, соответствует ли какой-либо бит? У меня есть таблица User с битовой маской для всех ролей, к которым принадлежит пользователь, и я бы хотел выбрать всех пользователей, у которых есть какая-либо из ролей в поставляемой битмаске. Таким образом, используя приведенные ниже данные, битмаска ролей 6 (дизайнер + программист) должна выбрать Dave, Charlie и Susan, но не 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

Любые идеи? Спасибо.

4b9b3361

Ответ 1

Ответ на ваш вопрос заключается в использовании Побитового & следующим образом:

SELECT * FROM UserTable WHERE Roles & 6 != 0

6 можно обменять на любую комбинацию вашего битового поля, где вы хотите проверить, что любой пользователь имеет один или несколько из этих битов. Когда я пытаюсь проверить это, я обычно считаю полезным написать эту запись в двоичном формате. Ваша пользовательская таблица выглядит так:

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

Ваш тест (6) - это

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

Если мы пройдем через каждого человека, делающего битвейз И против теста мы получим следующее:

        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) 

Вышеупомянутое должно продемонстрировать, что любые записи, в которых результат не равен нулю, имеют один или несколько запрошенных флагов.

Изменить: здесь тестовый пример должен проверить этот

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

или

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

или

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

Ответ 2

Используйте Transact-SQL побитовый оператор AND "&" и сравните результат с нолем. Еще лучше, вместо того, чтобы кодировать роли как биты целочисленного столбца, используйте булевы столбцы, по одному для каждой роли. Тогда ваш запрос будет просто конструктором и программистом. Если вы ожидаете, что роли будут сильно меняться в течение всего срока службы вашего приложения, используйте таблицу "многие-ко-многим", чтобы сопоставить связь между пользователями и их ролями. обе альтернативы более переносимы, чем полагаться на существование побитового оператора AND.

Ответ 3

SELECT * FROM UserTable WHERE Roles & 6 > 0

Ответ 4

SELECT * FROM table WHERE mask1 и mask2 > 0

Ответ 5

Пример:

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

Ответ 6

Чтобы найти всех программистов, используйте:

SELECT * FROM UserTable WHERE Roles & 2 = 2