需求举例:

某动物园对动物的投喂有以下规定:
     苹果可以去投喂鹿、猴子、熊猫
     竹子可以去投喂熊猫、竹鼠
     树叶可以去投喂兔子、鹿
现在饲养员携带苹果、树叶,他可以投喂哪些动物?

分析

上述情景中,饲养员、动物针对投放的食物在多种条件下匹配且最少有一项符合条件就确认投喂


位运算 &

简单回顾 & 的用法

按位“与”操作符,<font color = red>如果两个数的二进制,相同位数都是1,则改位结果为1,否则是0</font>。以下举例:

int a = 5;
int b = 4;

5的二进制:0000 0000 0000 0101
4的二进制:0000 0000 0000 0100

a & b = 0000 0000 0000 0100 
0000 0000 0000 0100 ==> 4   //转为十进制是4 
借助 &
  1. mysql支持位运算的操作逻辑,如 SELECT * FROM table WHERE a & 5 <> ?;
  2. 回到上面的需求,假设我们使用位运算,可以让苹果代表个位、竹子代表十位、树叶就代表百位(二进制下),由于二进制下每一位只有0和1的值,那么可以规定该动物允许投喂这种食物赋值1,不允许投喂就赋值0。以鹿为例:吃苹果、不吃竹子、吃树叶,则用二进制表示为101:
    1       0         1  
    吃树叶  不吃竹子  吃苹果
  1. 保存数据库时,101就是鹿的喂食数据,将二进制转为十进制101 —> 5,即保存鹿信息时,有一个食物的字段的数据为5
  2. 上面的需求,要去查询允许投喂苹果、树叶的动物,做条件筛选时请求会携带着要查询食物参数,那么该请求参数先进行处理为101(同上面的方式)-> 5,那么我们可以把 {food:5} 放入请求中,后台接收处理
  3. 现在我们一个个比较下各动物的投食数据:

鹿的食物信息为 101 -> 5
猴子的食物信息 100 -> 4
熊猫的食物信息 110 -> 6
竹鼠的食物信息 010 -> 2
兔子的食物信息 001 -> 1

菜单 鹿 猴子 熊猫 竹鼠 兔子
数据运算 5 & 5 4 & 5 6 & 5 2 & 5 1 & 5
转为二进制 101 & 101 100 & 101 110 & 101 010 & 101 001 & 101
结果 101 -> 5 100 -> 4 100 -> 4 000 -> 0 001 -> 1

从上面的结果可以得出,唯一不符合条件的动物为竹鼠,其经过位运算后的值是0,其他只要存在符合项就要大于0。SQL应为:

SELECT name FROM zoo_animal WHERE food & 5 > 0;

即可查寻出所有的符合条件的动物


变更

全部符合

假如现在需求更改,必须是确定这个动物既吃苹果又吃树叶才允许投递(必须条件一致,不多不少),那么改为:

SELECT name FROM zoo_animal WHERE (food & 5) = 5;
条件规则

新增: 现在又多了一种食物,比如香蕉,现在动物信息表中所有的数据都是基于苹果、竹子、树叶所整合出来的,如何做到最小的变动,我们可以让每一次新增的食物的位放到最前面,现在就是千位上代表香蕉,因为新添加的食物不会出现在原本的动物身上,所以原本的动物就变成了:

鹿: 0101 -> 5 
猴子: 0100 -> 4
熊猫的食物信息: 0110 -> 6
竹鼠的食物信息: 0010 -> 2
兔子的食物信息: 0001 -> 1

我们知道在位数前面加0,是不会更改数值的,如果运行原本动物吃香蕉,只需走重新维护动物信息的请求即可

删除: 删除不同于添加,删除的数据没有确定性,假如我们现在删除了竹子的信息,那么所有的食物信息都会出现差错,所以我们需要做一个规则的重建,即删除掉某一个信息时,应该重新把动物的食物信息重新按规则构建:

鹿: 11 -> 3 
猴子: 10 -> 2
熊猫的食物信息: 10 -> 2
竹鼠的食物信息: 00 -> 0
兔子的食物信息: 01 -> 1

修改:修改同删除,但实际场景出现的可能性较少(自我感觉,应该没人会去调整食物的排列顺序)