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

StackOverflow https://stackoverflow.com/questions/143712

  •  02-07-2019
  •  | 
  •  

Вопрос

Есть ли способ сравнить две битовые маски в Transact-SQL, чтобы увидеть, совпадает ли какой-либо из битов?У меня есть таблица пользователей с битовой маской для всех ролей, к которым принадлежит пользователь, и я хотел бы выбрать всех пользователей, у которых есть Любой из ролей в предоставленной битовой маске.Итак, используя приведенные ниже данные, битовая маска ролей из 6 (дизайнер + программист) должна выбрать Дейва, Чарли и Сьюзан, но не Ника.

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

Есть какие-нибудь идеи?Спасибо.

Это было полезно?

Решение

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

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

Другие советы

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

SELECT * FROM UserTable WHERE Roles & 6 > 0

ВЫБЕРИТЕ * ИЗ таблицы, ГДЕ mask1 и mask2 > 0

пример:

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

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

SELECT * FROM UserTable WHERE Roles & 2 = 2
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top