使用位运算,处理数据库中的"多选状态标识"
2017-07-12 20:43
211 查看
引言【摘自其他文章】: 最近在对公司以前的一个项目进行调整时发现,数据库中有很多表示“多选状态标识”的字段。“多选状态标识”可能描述的并不十分准确,在这里用我们项目中的几个例子进行说明一下。 例一:表示某个商家是否支持多种会员卡打折(如有金卡、银卡、其他卡等),项目中的以往的做法是:在每条商家记录中为每种会员卡建立一个标志位字段。如图: 其中蓝色区域的三个整形字段分别表示三种会员卡。当值为“1”时表示当前商家支持这种会员卡打折,反之“0”则表示不支持。 例二:表示系统字典表中某种类型方式,会在哪个功能模块中调用。如某种“支付方式”可能在“收银模块”中会用到,在“结算模块”中也会用到。如图: 用多字段来表示“多选标识”存在一定的缺点:首先这种设置方式很明显不符合数据库设计第一范式,增加了数据冗余和存储空间。再者,当业务发生变化时,不利于灵活调整。比如,增加了一种新的会员卡类型时,需要在数据表中增加一个新的字段,以适应需求的变化。 因此,我们在重新审视数据库设计时,我的一位同事提出了一种代替方式:将多个状态标识字段合并成一个字段,并把这个字段改成字符串型,对多选状态值以字符串数组的方式保存(一个以逗号分隔的字符串:“1,2,3”)。表的结构变成如下: “MEMBERCARD”字段中,当存在“1”时表示支持金卡打折,“2”时表示支持银卡打折,“3”表示支持其他卡打折。 这样调整的好处,不仅消除相同字段的冗余,而且当增加新的会员卡类别时,不需增加新的字段。但带来新的问题:在数据查询时,需要对字符串进行分隔。并且字符串类型的字段在查询效率和存储空间上不如整型字段。 总的来说,上面调整的思路是正确的,但不够自然。我后来考虑了一下,觉得可以用“位”来解决这个问题:二进制的“位”本来就有表示状态的作用。可以用下面各个位来分别表示不同种类的会员卡打折支持: 这样,“MEMBERCARD”字段仍采用整型。当某个商家支持金卡打折时,则保存“1(0001)”,支持银卡时,则保存“2(0010)”,两种都支持,则保存“3(0011)”。其他类似。表结构如图: 我们在编写SQL语句时,只需要通过“位”的与运算,就能简单的查询出想要数据:[java] viewplain copy//查询支持金卡打折的商家信息: select * from factory where MEMBERCARD & b'0001' 或者: select * from factory where MEMBERCARD & 1 //查询支持银卡打折的商家信息: select * from factory where MEMBERCARD & b'0010' 或者: Select * from factory where MEMBERCARD & 2 通过这样的处理方式既节省存储空间,查询时又简单方便。以上sql语句为MySQL的语法,其他数据库方法类似。并且“b'0010'”二进制的表示方式的语法是在5.0以后的版本才有。以上来源自: http://blog.csdn.net/wangdejun/article/details/5692033实际操作【实战一把】: 更新后: 后记【位运算】:
CREATETABLE`news`(
`id`int(11)NOTNULLAUTO_INCREMENTCOMMENT'主键ID',
`title`varchar(20)NOTNULLCOMMENT'文章标题',
`status`int(2)NOTNULLCOMMENT'状态1:是否置顶;2:是否点赞;4:是否推荐',
PRIMARYKEY(`id`)
)ENGINE=MyISAMAUTO_INCREMENT=7DEFAULTCHARSET=utf8;数据表的原始数据:
【更新】status=置顶;
updatenewssetstatus=status|1whereid=1
【更新】status=点赞;updatenewssetstatus=status|2whereid=1
【更新】status=推荐;updatenewssetstatus=status|4whereid=2
【选择】status=推荐;
select*fromnewswherestatus&4=4
【选择】status=置顶&推荐&点赞;;
select*fromnewswherestatus&7=7
【选择】status=置顶&推荐;
select*fromnewswherestatus&3=3
【选择】status=不置顶&不推荐;
select*fromnewswherestatus&1!=1andstatus&4!=4
【选择】status=不置顶|不点赞;
select*fromnewswherestatus&1!=1orstatus&2!=2
【更新某记录】status=推荐,为不推荐;
updatenewssetstatus=status^4whereid=1更新前:
按位与运算
按位与运算符"&"是双目运算符。
其功能是参与运算的两数各对应的二进位相与。只有对应的两个二进位均为1时,结果位才为1,否则为0。
参与运算的数以补码方式出现。
例如:9&5可写算式如下:
00001001(9的二进制补码)
&00000101(5的二进制补码)
00000001(1的二进制补码)
可见9&5=1。
按位与运算通常用来对某些位清0或保留某些位。
例如把a的高八位清0,保留低八位,可作a&255运算(255的二进制数为0000000011111111)。
按位或运算
按位或运算符“|”是双目运算符。其功能是参与运算的两数各对应的二进位相或。
只要对应的二个二进位有一个为1时,结果位就为1。参与运算的两个数均以补码出现。
例如:9|5可写算式如下:
00001001
|00000101
00001101(十进制为13)
可见9|5=13
按位异或运算
按位异或运算符“^”是双目运算符。其功能是参与运算的两数各对应的二进位相异或,当两对应的二进位相异时,结果为1。
参与运算数仍以补码出现,
例如9^5可写成算式如下:
00001001
^00000101
00001100(十进制为12)
求反运算
求反运算符~为单目运算符,具有右结合性。
其功能是对参与运算的数的各二进位按位求反。
例如~9的运算为:
~(0000000000001001)
结果为:1111111111110110
左移运算
左移运算符“<<”是双目运算符。其功能把“<<”左边的运算数的各二进位全部左移若干位,由“<<”右边的数指定移动的位数,高位丢弃,低位补0。
例如:
a<<4
指把a的各二进位向左移动4位。
如a=00000011(十进制3),左移4位后为00110000(十进制48)。
右移运算
右移运算符“>>”是双目运算符。
其功能是把“>>”左边的运算数的各二进位全部右移若干位,“>>”右边的数指定移动的位数。
例如:
设a=15,
a>>2
表示把000001111右移为00000011(十进制3)。注意:对于有符号数,在右移时,符号位将随同移动。当为正数时,最高位补0,而为负数时,符号位为1, 最高位是补0或是补1取决于编译系统的规定。TurboC和很多系统规定为补1
相关文章推荐
- 数据库设计——“多选状态标识”的处理
- 数据库设计——“多选状态标识”的处理
- sqlserver"无法删除数据库,因为该数据库当前正在使用"问题解决
- 无法删除数据库 "#Test",因为该数据库当前正在使用
- 尚未备份数据库 "***" 的日志尾部。如果该日志包含您不希望丢失的工作,请使用 BACKUP LOG WITH NORECOVERY 备份该日志。
- 关于Entity Framework更新的几种方式以及可能遇到的问题(附加类型“Model”的实体失败,因为相同类型的其他实体已具有相同的主键值)在使用 "Attach" 方法或者将实体的状态设置为 "Unchanged" 或 "Modified" 时如果图形中的任何实体具有冲突键值,则可能会发生上述行为
- sqlserver"无法删除数据库,因为该数据库当前正在使用"问题解决
- MSSQL数据库 "无法删除数据库 "***",因为该数据库当前正在使用" 解决方案
- R语言使用ODBC连接数据库PostgreSQL查询语句中含有""处理方法
- 使用PHP处理数据库数据如何将数据返回客户端并显示当前状态
- 【转】无法删除数据库 "#Test",因为该数据库当前正在使用
- 因为相同类型的其他实体已具有相同的主键值。在使用 "Attach" 方法或者将实体的状态设置为 "Unchanged" 或 "Modified" 。。。
- 尚未备份数据库 "TEST" 的日志尾部。如果该日志包含您不希望丢失的工作,请使用 BACKUP LOG WITH NORECOVERY 备份该日志。请使用 RESTORE 语句的 WITH REPL
- 转载 :sql server 2005 无法删除数据库 "#Test",因为该数据库当前正在使用
- 数据库设计——“多选状态标识”的处理
- sql server 2005 无法删除数据库 "#Test",因为该数据库当前正在使用
- 无法删除数据库 "aaa",因为该数据库当前正在使用
- 使用多线程处理弹出"提示气泡"任务
- SQL0286N 找不到页大小至少为 "8192"、许可使用授权标识 "db2inst" 的缺省表空间。
- 错误:因为相同类型的其他实体已具有相同的主键值。在使用 "Attach" 方法或者将实体的状态设置为 "Unchanged" 或 "Modified" 解决方法