最近做使用者許可權控制,遇到乙個需求,可以抽象為使用者的城市屬性都是多城市的,需要列出某城市集合的子集的使用者。
最初的使用者-城市關係表有如下範例資料,前一列為使用者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...