使用位运算,处理数据库中的"多选状态标识"

简介: 使用位运算,处理数据库中的"多选状态标识"
  • 引言【摘自其他文章】:  

   

    最近在对公司以前的一个项目进行调整时发现,数据库中有很多表示“多选状态标识”的字段。“多选状态标识”可能描述的并不十分准确,在这里用我们项目中的几个例子进行说明一下。

     例一:表示某个商家是否支持多种会员卡打折(如有金卡、银卡、其他卡等),项目中的以往的做法是:在每条商家记录中为每种会员卡建立一个标志位字段。如图:

 

     其中蓝色区域的三个整形字段分别表示三种会员卡。当值为“1”时表示当前商家支持这种会员卡打折,反之“0”则表示不支持。

 

     例二:表示系统字典表中某种类型方式,会在哪个功能模块中调用。如某种“支付方式”可能在“收银模块”中会用到,在“结算模块”中也会用到。如图:


     用多字段来表示“多选标识”存在一定的缺点:首先这种设置方式很明显不符合数据库设计第一范式,增加了数据冗余和存储空间。再者,当业务发生变化时,不利于灵活调整。比如,增加了一种新的会员卡类型时,需要在数据表中增加一个新的字段,以适应需求的变化。

 

     因此,我们在重新审视数据库设计时,我的一位同事提出了一种代替方式:将多个状态标识字段合并成一个字段,并把这个字段改成字符串型,对多选状态值以字符串数组的方式保存(一个以逗号分隔的字符串:“1,2,3”)。表的结构变成如下:



    “MEMBERCARD”字段中,当存在“1”时表示支持金卡打折,“2”时表示支持银卡打折,“3”表示支持其他卡打折。

     这样调整的好处,不仅消除相同字段的冗余,而且当增加新的会员卡类别时,不需增加新的字段。但带来新的问题:在数据查询时,需要对字符串进行分隔。并且字符串类型的字段在查询效率和存储空间上不如整型字段。

 

     总的来说,上面调整的思路是正确的,但不够自然。我后来考虑了一下,觉得可以用“位”来解决这个问题:二进制的“位”本来就有表示状态的作用。可以用下面各个位来分别表示不同种类的会员卡打折支持:

     这样,“MEMBERCARD”字段仍采用整型。当某个商家支持金卡打折时,则保存“1(0001)”,支持银卡时,则保存“2(0010)”,两种都支持,则保存“3(0011)”。其他类似。表结构如图:


我们在编写SQL语句时,只需要通过“位”的与运算,就能简单的查询出想要数据:

[java]  view plain  copy

  1. //查询支持金卡打折的商家信息:  
  2. select * from factory where MEMBERCARD & b'0001'  
  3. 或者:  
  4. select * from factory where MEMBERCARD & 1  
  5.  
  6. //查询支持银卡打折的商家信息:  
  7. select * from factory where MEMBERCARD & b'0010'  
  8. 或者:  
  9. Select * from factory where MEMBERCARD & 2  

 

     通过这样的处理方式既节省存储空间,查询时又简单方便。以上sql语句为MySQL的语法,其他数据库方法类似。并且“b'0010'”二进制的表示方式的语法是在5.0以后的版本才有。



以上来源自: http://blog.csdn.net/wangdejun/article/details/5692033




  • 实际操作【实战一把】:


  1. CREATE TABLE `news`(
  2.  `id` int(11) NOT NULL AUTO_INCREMENT COMMENT '主键ID',
  3.  `title` varchar(20) NOT NULL COMMENT '文章标题',
  4.  `status` int(2) NOT NULL COMMENT '状态 1:是否置顶;2:是否点赞;4:是否推荐',
  5.  PRIMARY KEY (`id`)
  6. ) ENGINE=MyISAM AUTO_INCREMENT=7 DEFAULT CHARSET=utf8;



数据表的原始数据:



  1. 【更新】status =置顶;
  2. update news set status = status |1 where id =1
  3. 【更新】status =点赞; update news set status = status | 2 where id = 1
  4. 【更新】status =推荐;update news set status = status | 4 where id = 2



  1. 【选择】status =推荐;
  2. select *from news where status &4=4

 


  1. 【选择】status =置顶&推荐&点赞;;
  2. select *from news where status &7=7
  3. 【选择】status =置顶&推荐;
  4. select *from news where status &3=3
  5. 【选择】status =不置顶&不推荐;
  6. select *from news where status &1!=1and status &4!=4


  1. 【选择】status =不置顶|不点赞;
  2. select *from news where status &1!=1or status &2!=2



  1. 【更新某记录】status =推荐,为不推荐;
  2. update news set status = status ^4 where id =1



更新前:



 


更新后:




 


 


  • 后记【位运算】:


按位与运算

  1. 按位与运算符"&"是双目运算符。
  2. 其功能是参与运算的两数各对应的二进位相与。只有对应的两个二进位均为1时,结果位才为1,否则为0
  3. 参与运算的数以补码方式出现。
  4. 例如:9&5可写算式如下:
  5.    00001001      (9的二进制补码)
  6.   &00000101    (5的二进制补码)
  7.    00000001       (1的二进制补码)
  8. 可见9&5=1
  9. 按位与运算通常用来对某些位清0或保留某些位。
  10. 例如把a 的高八位清0,保留低八位,可作a&255运算(255的二进制数为0000000011111111)。


按位或运算

  1. 按位或运算符“|”是双目运算符。其功能是参与运算的两数各对应的二进位相或。
  2. 只要对应的二个二进位有一个为1时,结果位就为1。参与运算的两个数均以补码出现。
  3. 例如:9|5可写算式如下:
  4.    00001001
  5.   |00000101
  6.    00001101    (十进制为13)
  7. 可见9|5=13


按位异或运算

  1. 按位异或运算符“^”是双目运算符。其功能是参与运算的两数各对应的二进位相异或,当两对应的二进位相异时,结果为1
  2. 参与运算数仍以补码出现,
  3. 例如9^5可写成算式如下:
  4.    00001001
  5.   ^00000101
  6.    00001100    (十进制为12)


求反运算

  1. 求反运算符~为单目运算符,具有右结合性。
  2. 其功能是对参与运算的数的各二进位按位求反。
  3. 例如~9的运算为:
  4.    ~(0000000000001001)
  5. 结果为:1111111111110110


左移运算

  1. 左移运算符“<<”是双目运算符。其功能把“<<”左边的运算数的各二进位全部左移若干位,由“<<”右边的数指定移动的位数,高位丢弃,低位补0
  2. 例如:
  3.    a<<4
  4. 指把a的各二进位向左移动4位。
  5. a=00000011(十进制3),左移4位后为00110000(十进制48)。


右移运算

  1. 右移运算符“>>”是双目运算符。
  2. 其功能是把“>>”左边的运算数的各二进位全部右移若干位,“>>”右边的数指定移动的位数。
  3. 例如:
  4.      a=15
  5.    a>>2
  6. 表示把000001111右移为00000011(十进制3)。



注意:对于有符号数,在右移时,符号位将随同移动。当为正数时,最高位补0,而为负数时,符号位为1,

        最高位是补0或是补1 取决于编译系统的规定。Turbo C和很多系统规定为补1


相关文章
|
3月前
|
缓存 关系型数据库 BI
使用MYSQL Report分析数据库性能(下)
使用MYSQL Report分析数据库性能
172 3
|
3月前
|
关系型数据库 MySQL 数据库
自建数据库如何迁移至RDS MySQL实例
数据库迁移是一项复杂且耗时的工程,需考虑数据安全、完整性及业务中断影响。使用阿里云数据传输服务DTS,可快速、平滑完成迁移任务,将应用停机时间降至分钟级。您还可通过全量备份自建数据库并恢复至RDS MySQL实例,实现间接迁移上云。
|
3月前
|
关系型数据库 MySQL 数据库
阿里云数据库RDS费用价格:MySQL、SQL Server、PostgreSQL和MariaDB引擎收费标准
阿里云RDS数据库支持MySQL、SQL Server、PostgreSQL、MariaDB,多种引擎优惠上线!MySQL倚天版88元/年,SQL Server 2核4G仅299元/年,PostgreSQL 227元/年起。高可用、可弹性伸缩,安全稳定。详情见官网活动页。
858 152
|
4月前
|
存储 运维 关系型数据库
从MySQL到云数据库,数据库迁移真的有必要吗?
本文探讨了企业在业务增长背景下,是否应从 MySQL 迁移至云数据库的决策问题。分析了 MySQL 的优势与瓶颈,对比了云数据库在存储计算分离、自动化运维、多负载支持等方面的优势,并提出判断迁移必要性的五个关键问题及实施路径,帮助企业理性决策并落地迁移方案。
|
3月前
|
关系型数据库 MySQL 分布式数据库
阿里云PolarDB云原生数据库收费价格:MySQL和PostgreSQL详细介绍
阿里云PolarDB兼容MySQL、PostgreSQL及Oracle语法,支持集中式与分布式架构。标准版2核4G年费1116元起,企业版最高性能达4核16G,支持HTAP与多级高可用,广泛应用于金融、政务、互联网等领域,TCO成本降低50%。
|
3月前
|
关系型数据库 分布式数据库 数据库
阿里云数据库收费价格:MySQL、PostgreSQL、SQL Server和MariaDB引擎费用整理
阿里云数据库提供多种类型,包括关系型与NoSQL,主流如PolarDB、RDS MySQL/PostgreSQL、Redis等。价格低至21元/月起,支持按需付费与优惠套餐,适用于各类应用场景。
|
3月前
|
SQL 关系型数据库 MySQL
Mysql数据恢复—Mysql数据库delete删除后数据恢复案例
本地服务器,操作系统为windows server。服务器上部署mysql单实例,innodb引擎,独立表空间。未进行数据库备份,未开启binlog。 人为误操作使用Delete命令删除数据时未添加where子句,导致全表数据被删除。删除后未对该表进行任何操作。需要恢复误删除的数据。 在本案例中的mysql数据库未进行备份,也未开启binlog日志,无法直接还原数据库。
|
3月前
|
Ubuntu 安全 关系型数据库
安装与配置MySQL 8 on Ubuntu,包括权限授予、数据库备份及远程连接指南
以上步骤提供了在Ubuntu上从头开始设置、配置、授权、备份及恢复一个基础但完整的MySQL环境所需知识点。
477 7
|
3月前
|
缓存 监控 关系型数据库
使用MYSQL Report分析数据库性能(上)
最终建议:当前系统是完美的读密集型负载模型,优化重点应放在减少行读取量和提高数据定位效率。通过索引优化、分区策略和内存缓存,预期可降低30%的CPU负载,同时保持100%的缓冲池命中率。建议每百万次查询后刷新统计信息以持续优化
258 6

热门文章

最新文章