数据库设计——“多选状态标识”的处理
2010-06-24 16:55
155 查看
最近在对公司以前的一个项目进行调整时发现,数据库中有很多表示“多选状态标识”的字段。“多选状态标识”可能描述的并不十分准确,在这里用我们项目中的几个例子进行说明一下。
例一:表示某个商家是否支持多种会员卡打折(如有金卡、银卡、其他卡等),项目中的以往的做法是:在每条商家记录中为每种会员卡建立一个标志位字段。如图:
![](http://hi.csdn.net/attachment/201006/24/0_12773692744yA6.gif)
其中蓝色区域的三个整形字段分别表示三种会员卡。当值为“1”时表示当前商家支持这种会员卡打折,反之“0”则表示不支持。
例二:表示系统字典表中某种类型方式,会在哪个功能模块中调用。如某种“支付方式”可能在“收银模块”中会用到,在“结算模块”中也会用到。如图:
![](http://hi.csdn.net/attachment/201006/24/0_1277369375itv7.gif)
用多字段来表示“多选标识”存在一定的缺点:首先这种设置方式很明显不符合数据库设计第一范式,增加了数据冗余和存储空间。再者,当业务发生变化时,不利于灵活调整。比如,增加了一种新的会员卡类型时,需要在数据表中增加一个新的字段,以适应需求的变化。
因此,我们在重新审视数据库设计时,我的一位同事提出了一种代替方式:将多个状态标识字段合并成一个字段,并把这个字段改成字符串型,对多选状态值以字符串数组的方式保存(一个以逗号分隔的字符串:“1,2,3”)。表的结构变成如下:
![](http://hi.csdn.net/attachment/201006/24/0_1277369284N6Rd.gif)
“MEMBERCARD”字段中,当存在“1”时表示支持金卡打折,“2”时表示支持银卡打折,“3”表示支持其他卡打折。
这样调整的好处,不仅消除相同字段的冗余,而且当增加新的会员卡类别时,不需增加新的字段。但带来新的问题:在数据查询时,需要对字符串进行分隔。并且字符串类型的字段在查询效率和存储空间上不如整型字段。
总的来说,上面调整的思路是正确的,但不够自然。我后来考虑了一下,觉得可以用“位”来解决这个问题:二进制的“位”本来就有表示状态的作用。可以用下面各个位来分别表示不同种类的会员卡打折支持:
![](http://hi.csdn.net/attachment/201006/24/0_1277369289Jh82.gif)
这样,“MEMBERCARD”字段仍采用整型。当某个商家支持金卡打折时,则保存“1(0001)”,支持银卡时,则保存“2(0010)”,两种都支持,则保存“3(0011)”。其他类似。表结构如图:
![](http://hi.csdn.net/attachment/201006/24/0_12773693790Kaj.gif)
我们在编写SQL语句时,只需要通过“位”的与运算,就能简单的查询出想要数据:
通过这样的处理方式既节省存储空间,查询时又简单方便。以上sql语句为MySql的语法,其他数据库方法类似。并且“b'0010'”二进制的表示方式的语法是在5.0以后的版本才有。
例一:表示某个商家是否支持多种会员卡打折(如有金卡、银卡、其他卡等),项目中的以往的做法是:在每条商家记录中为每种会员卡建立一个标志位字段。如图:
![](http://hi.csdn.net/attachment/201006/24/0_12773692744yA6.gif)
其中蓝色区域的三个整形字段分别表示三种会员卡。当值为“1”时表示当前商家支持这种会员卡打折,反之“0”则表示不支持。
例二:表示系统字典表中某种类型方式,会在哪个功能模块中调用。如某种“支付方式”可能在“收银模块”中会用到,在“结算模块”中也会用到。如图:
![](http://hi.csdn.net/attachment/201006/24/0_1277369375itv7.gif)
用多字段来表示“多选标识”存在一定的缺点:首先这种设置方式很明显不符合数据库设计第一范式,增加了数据冗余和存储空间。再者,当业务发生变化时,不利于灵活调整。比如,增加了一种新的会员卡类型时,需要在数据表中增加一个新的字段,以适应需求的变化。
因此,我们在重新审视数据库设计时,我的一位同事提出了一种代替方式:将多个状态标识字段合并成一个字段,并把这个字段改成字符串型,对多选状态值以字符串数组的方式保存(一个以逗号分隔的字符串:“1,2,3”)。表的结构变成如下:
![](http://hi.csdn.net/attachment/201006/24/0_1277369284N6Rd.gif)
“MEMBERCARD”字段中,当存在“1”时表示支持金卡打折,“2”时表示支持银卡打折,“3”表示支持其他卡打折。
这样调整的好处,不仅消除相同字段的冗余,而且当增加新的会员卡类别时,不需增加新的字段。但带来新的问题:在数据查询时,需要对字符串进行分隔。并且字符串类型的字段在查询效率和存储空间上不如整型字段。
总的来说,上面调整的思路是正确的,但不够自然。我后来考虑了一下,觉得可以用“位”来解决这个问题:二进制的“位”本来就有表示状态的作用。可以用下面各个位来分别表示不同种类的会员卡打折支持:
![](http://hi.csdn.net/attachment/201006/24/0_1277369289Jh82.gif)
这样,“MEMBERCARD”字段仍采用整型。当某个商家支持金卡打折时,则保存“1(0001)”,支持银卡时,则保存“2(0010)”,两种都支持,则保存“3(0011)”。其他类似。表结构如图:
![](http://hi.csdn.net/attachment/201006/24/0_12773693790Kaj.gif)
我们在编写SQL语句时,只需要通过“位”的与运算,就能简单的查询出想要数据:
//查询支持金卡打折的商家信息: 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以后的版本才有。
相关文章推荐
- 数据库设计——“多选状态标识”的处理
- 使用位运算,处理数据库中的"多选状态标识"
- 数据库设计——“多选状态标识”的处理
- 数据库设计——“多选状态标识”的处理
- JSP基础 指令page isErrorPage 标识当前页面是处理错误的 并 出错时返回状态码为500
- iOS 应用状态,状态切换与多任务处理
- #646 – 在按键按下事件处理程序中判断按键开关状态(Detecting a Key’s Toggle State in a Keypress Handler)
- 关于在ALV报表单元或行标识不同的颜色的处理
- 自定义控件开发的调试及DesignMode的状态处理
- Windows OS中处于stopping状态的Windows Services处理方法
- MOSS发生“未能转换部分或所有标识引用”错误的处理
- TCP server close_wait状态处理方法
- 网易云音乐对空状态的处理方法
- SubscriptionInfoUpdater监听卡状态广播的处理
- 如何处理参考文献及其标识
- Nokia S60如何处理302 HTTP状态[J2ME]
- Sys.WebForms.PageRequestManagerServerErrorException: 在服务器上处理请求时出现未知错误。服务器返回的状态码为: 500
- nginx一般的http请求建立处理,发送函数调用,以及各个phase的状态(等完善)
- vs2005入门 之 状态处理(Application,Seeeion,Cookie) [视频]
- Openfire Server presence(在线状态)消息处理流程