用位操作實現按子集篩選

2021-05-22 19:23:12 字數 2620 閱讀 9729

最近做使用者許可權控制,遇到乙個需求,可以抽象為使用者的城市屬性都是多城市的,需要列出某城市集合的子集的使用者。

最初的使用者-城市關係表有如下範例資料,前一列為使用者id,後一列是城市

1 anshan

1 beijing

1 baotou

1 baoding

1 beihai

1 baoji

1 chongqing

1 chengdu

2 anshan

2 beijing

3 baotou

3 baoding

3 beihai

4 baoji

4 shanghai

比如乙個城市集合是 [anshan, beijing, baotou, baoding, beihai, baoji],篩選出城市屬性是此集合子集的使用者,就是要城市屬性是 anshan 或 beijing 之類的,但沒有此集合以外城市的使用者。比如使用者 2 的城市是anshan 和 beijing,使用者 3 的城市是 baotou, baoding, beihai,都符合條件。使用者 4 雖然有 baoji,但還有 shanghai,是指定集合以外的城市,所以不符合。

經過試驗可以使用位操作,先把城市分離出單獨的表,城市 id 先用二進位制數表示,每個城市把不同的位置為 1 ,即城市 id 是 2 的冪

000000001 anshan

000000010 beijing

000000100 baotou

000001000 baoding

000010000 beihai

000100000 baoji

001000000 chongqing

010000000 chengdu

100000000 shanghai

然後使用者-城市關係改為某使用者所有城市的城市id之和

id 二進位制 

1 000111111

2 000000011

3 000011100

4 100100000

5 110000001

這裡集合 [anshan, beijing, baotou, baoding, beihai, baoji] 就可以表示成 111111,篩選時取當前使用者按位與的結果與前使用者值相同的為符合。

上述演示資料中的整數都是二進位制表示,實際儲存在資料庫裡的是它們的十進位制數,以下為篩選出城市集合為 111111 的具體 sql 語句範例,這裡 111111 已轉換成普通十進位制數 63:

select user_id, city_sum from user_city where (city_sum & 63)=city_sum;

此方案城市 id 是2的冪, 要求字段長度比較大,mysql 無符號 bigint 最大是18446744073709551615。所以 城市id 和使用者的城市屬性都用無符號 bigint。

最後列出此例子可用的實際 sql 語句,這是 mysql 資料庫的,其它資料庫可依理類推:

create table `city` (

`city_id` bigint(20) unsigned not null default '0',

`city_name` varchar(20) not null,

primary key  (`city_id`)

) engine=innodb default charset=latin1 comment='城市,城市id是按位遞增的二進位制數';

insert into `city` values (1, 'anshan');

insert into `city` values (2, 'beijing');

insert into `city` values (4, 'baotou');

insert into `city` values (8, 'baoding');

insert into `city` values (16, 'beihai');

insert into `city` values (32, 'baoji');

insert into `city` values (64, 'chongqing');

insert into `city` values (128, 'chengdu');

insert into `city` values (256, 'shanghai');

create table `user_city` (

`user_id` int(11) not null,

`city_sum` bigint(20) unsigned default '0',

primary key  (`user_id`)

) engine=myisam default charset=latin1 comment='使用者-城市關係';

insert into `user_city` values (1, 63);

insert into `user_city` values (2, 3);

insert into `user_city` values (3, 28);

insert into `user_city` values (4, 288);

insert into `user_city` values (5, 385);

A B按位操作實現

problem 1 description write a function that add two numbers a and b.you should not use or any arithmetic operators.a與b均為32位整數。不用加法運算子的話考慮按位計算。首先 a b如果...

c c 按位操作

因為有時候需要大量的標誌位來判斷當前狀態等。使用太多的int,bool等會使得程式不 漂亮 這時候需要 位 操作來解決 建立乙個標誌位 unsigned int globalmark 0 在定義一些巨集,如 define control w 0x01 define control a 0x02 de...

c c 按位操作

因為有時候需要大量的標誌位來判斷當前狀態等。使用太多的int,bool等會使得程式不 漂亮 這時候需要 位 操作來解決 建立乙個標誌位 unsigned int globalmark 0 在定義一些巨集,如 define control w 0x01 define control a 0x02 de...