mysql 条件位运算实现多值存储

一、多值存储

  mysql 条件位运算位运算实现多值存储,方法适合数据范围有限,且不会变更在业务上往往会出现多选的情况,例:选择 周一 至 周日 随意组合;

数据在设计时就会如何去储存?

  • 一种是一般是在储存是以某种方式隔开,例如:1,2,3代表选择了 周一、 周二、周三;
  • 另一种就是使用,mysql的位运算;字段类型为 int(3);

七个二进制分别代表 周一至周日,0-未选 1-选中,例: 选择了周日、周一、 周二。

周一周二周三周四周五周六周日
110001

对应二进制位:11000001,数据库储存十进制:67

注意:

mysql位运算,一个字段表示多选值;这种方式可以提高查询效率,减少like语句的应用;


这种方式,建议每次参数都全量传。比如张三,第一次勾选了周一,第二次想新增周三、周四,那么前端传值:1,8,16;

二、设计

星期码值表
在这里插入图片描述

数据库存的数据
在这里插入图片描述

三、相关sql

3.1 关键sql

-- 查询包含周四的
SELECT * FROM test_weeks WHERE weeks & 8;
-- 查询不包含周四的
SELECT * FROM test_weeks WHERE !(weeks & 8);
-- 查询包含周一or周四的
SELECT * FROM test_weeks WHERE weeks & (1+8);
SELECT * FROM test_weeks WHERE weeks & 1 or weeks & 8;
-- 查询包含周一and周四的
SELECT * FROM test_weeks WHERE weeks & 1 and weeks & 8;-- 新增周四、周五;不建议,如果已经包含周四、周五了,这种方法计算出来的码值不对。
UPDATE test_weeks set weeks = weeks + 8 + 16 WHERE id = 3-- 减少周四、周五;不建议,如果已经不含周四、周五了,这种方法计算出来的码值不对
UPDATE test_weeks set weeks = weeks - 8 - 16 WHERE id = 3

3.1.1 根据名字,更新数据,将某人值班信息增加周四、周五

sumNum=8+16;

<update id="addDutyAndBin2">UPDATE mybatisx_duty_info<![CDATA[  set weeks = weeks | #{sumNum},]]><!--LPAD函数是MySQL中用于实现对字符串的左侧填充操作的函数。它的语法格式为:LPAD(str,len,padstr) -->weeks_bin=LPAD(bin( weeks | #{sumNum}),8,'0')WHERE name = #{name}</update>

3.1.2 根据名字,更新数据,将某人值班信息去掉周四、周五

  • 如果该人有周四、周五的值班信息,可以用【3.1 关键sql】最后一条sql;
  • 如果该人有周四、周五的值班信息,想实现【3.1.1】,这种情况写不了,没有对应的位运算符;

四、建表语句

星期枚举表:

SET NAMES utf8mb4;
SET FOREIGN_KEY_CHECKS = 0;-- ----------------------------
-- Table structure for mybatisx_week
-- ----------------------------
DROP TABLE IF EXISTS `mybatisx_week`;
CREATE TABLE `mybatisx_week`  (`id` int(0) NOT NULL,`week_ten` int(0) NULL DEFAULT NULL,`week_bin` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL,`remark` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL,PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci COMMENT = '星期枚举表' ROW_FORMAT = Dynamic;-- ----------------------------
-- Records of mybatisx_week
-- ----------------------------
INSERT INTO `mybatisx_week` VALUES (1, 1, '0000001', '星期日');
INSERT INTO `mybatisx_week` VALUES (2, 2, '0000010', '星期一');
INSERT INTO `mybatisx_week` VALUES (3, 4, '0000100', '星期二');
INSERT INTO `mybatisx_week` VALUES (4, 8, '0001000', '星期三');
INSERT INTO `mybatisx_week` VALUES (5, 16, '0010000', '星期四');
INSERT INTO `mybatisx_week` VALUES (6, 32, '0100000', '星期五');
INSERT INTO `mybatisx_week` VALUES (7, 64, '1000000', '星期六');SET FOREIGN_KEY_CHECKS = 1;

值班表:

CREATE TABLE `mybatisx_duty_info` (`id` int NOT NULL AUTO_INCREMENT,`weeks` int DEFAULT NULL,`weeks_bin` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT NULL,`name` varchar(255) DEFAULT NULL,PRIMARY KEY (`id`) USING BTREE
) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='值班表';

五、代码

5.1 查询周日、周三都值班的人

5.1.1 代码

 /**** ==>  Preparing: SELECT * FROM mybatisx_duty_info WHERE weeks & ? and weeks & ?* ==> Parameters: 1(Integer), 8(Integer)*/@Testpublic void testAnd(){//查一下周一和周四都值班的人;//周一:1;周四:8Integer[] weekArr={1,8};List<Integer> weekList = Arrays.asList(weekArr);List<MybatisxDutyInfo> mybatisxDutyInfos = mybatisxDutyInfoService.listByBinAnd(weekList);System.out.println("周一和周四都值班的人:"+ JSON.toJSONString(mybatisxDutyInfos));}

5.1.2 mybatis.xml

<select id="listByWeekOfAnd" resultType="com.qian.mybatisx.domain.MybatisxDutyInfo">SELECT *FROM mybatisx_duty_info<where><if test="weekList!=null and weekList.size >0"><foreach collection="weekList"  item="week"><![CDATA[ and weeks & #{week}]]></foreach></if></where></select>

5.2 查询包含周日or周三的

5.2.1 代码

/*** ==>  Preparing: SELECT * FROM mybatisx_duty_info WHERE weeks & ?* ==> Parameters: 72(Integer)*/@Testpublic void testOr() {//查询包含周日or周三的//周日:64;周四:8Integer[] weekArr={64,8};List<Integer> weekList = Arrays.asList(weekArr);List<MybatisxDutyInfo> mybatisxDutyInfos = mybatisxDutyInfoService.listByBinOr(weekList);System.out.println("周日or周三值班的人:"+ JSON.toJSONString(mybatisxDutyInfos));}
@Overridepublic List<MybatisxDutyInfo> listByBinOr(List<Integer> weekList) {if (CollectionUtils.isEmpty(weekList)){return null;}//mybatis的<foreach>标签里,相加不好写,so,在业务层加上int sum=0;for (Integer integer : weekList) {sum+=integer;}return mybatisxDutyInfoMapper.listByWeekOfOrSum(sum);}

5.2.2 mybatis.xml

<select id="listByWeekOfOrSum" resultType="com.qian.mybatisx.domain.MybatisxDutyInfo">SELECT *FROM mybatisx_duty_info<where><if test="sum >0"><![CDATA[ and  weeks & #{sum}]]></if></where></select>

5.3 查询不包含周二的

5.3.1 代码

 /**** ==>  Preparing: SELECT * FROM mybatisx_duty_info WHERE !(weeks & ?)* ==> Parameters: 2(Integer)*/@Testpublic void testNotIs() {//查询不包含周二的//周二:2Integer week=2;List<MybatisxDutyInfo> mybatisxDutyInfos = mybatisxDutyInfoService.listByBinNotIs(week);System.out.println("不包含周二值班的人:"+ JSON.toJSONString(mybatisxDutyInfos));}

5.3.2 mybatis.xml

<select id="listByBinNotIs" resultType="com.qian.mybatisx.domain.MybatisxDutyInfo">SELECT *FROM mybatisx_duty_info<where><if test="week !=null and week.tostring!='null'"><![CDATA[ and  !(weeks & #{week})]]></if></where></select>

5.4 修改值班日期为:周一、周三、周四;

5.4.1 代码

/*** 【建议这样:参数传全量的】* 张三值班改为周一、周三、周四;* 计算二进制:select bin(3);** 位数不足补0:SELECT LPAD(bin(3),8,'0')*/@Testpublic void testUpdateDuty() {//周一周三周四Integer[] weekArr={1,8,16};List<Integer> weekList = Arrays.asList(weekArr);mybatisxDutyInfoService.updateDuty(weekList,"张三");}
@Overridepublic void updateDuty(List<Integer> weekList, String name) {//sum表示要添加的码值之和Integer sum=0;for (Integer week : weekList) {sum+=week;}mybatisxDutyInfoMapper.updateDuty(sum,name);}

5.4.2 mybatis.xml

<update id="updateDuty">UPDATE mybatisx_duty_info set weeks =  #{sumNum},<!--LPAD函数是MySQL中用于实现对字符串的左侧填充操作的函数。它的语法格式为:LPAD(str,len,padstr) -->weeks_bin=LPAD(bin(#{sumNum}),8,'0')WHERE name = #{name}</update>

六、Java 位运算的常用方法封装

package com.qian.mybatisx.util;/*** Java 位运算的常用方法封装<br>*/
public class BitUtils {/*** 获取运算数指定位置的值<br>* 例如: 0000 1011 获取其第 0 位的值为 1, 第 2 位 的值为 0<br>** @param source*            需要运算的数* @param pos*            指定位置 (0<=pos<=7)* @return 指定位置的值(0 or 1)*/public static byte getBitValue(byte source, int pos) {return (byte) ((source >> pos) & 1);}/*** 将运算数指定位置的值置为指定值<br>* 例: 0000 1011 需要更新为 0000 1111, 即第 2 位的值需要置为 1<br>** @param source*            需要运算的数* @param pos*            指定位置 (0<=pos<=7)* @param value*            只能取值为 0, 或 1, 所有大于0的值作为1处理, 所有小于0的值作为0处理** @return 运算后的结果数*/public static byte setBitValue(byte source, int pos, byte value) {byte mask = (byte) (1 << pos);if (value > 0) {source |= mask;} else {source &= (~mask);}return source;}/*** 将运算数指定位置取反值<br>* 例: 0000 1011 指定第 3 位取反, 结果为 0000 0011; 指定第2位取反, 结果为 0000 1111<br>** @param source** @param pos*            指定位置 (0<=pos<=7)** @return 运算后的结果数*/public static byte reverseBitValue(byte source, int pos) {byte mask = (byte) (1 << pos);return (byte) (source ^ mask);}/*** 检查运算数的指定位置是否为1<br>** @param source*            需要运算的数* @param pos*            指定位置 (0<=pos<=7)* @return true 表示指定位置值为1, false 表示指定位置值为 0*/public static boolean checkBitValue(long source, int pos) {source = (long) (source >>> pos);return (source & 1) == 1;}/*** 入口函数做测试<br>** @param args*/public static void main(String[] args) {int param = 3;System.out.println(getBitValue(Byte.parseByte(param+""),2));// 取十进制 11 (二级制 0000 1011) 为例子long source = 256;// 取第2位值并输出, 结果应为 0000 1011for (byte i = 7; i >= 0; i--) {System.out.printf("%d ", getBitValue((byte) source, i));}// 将第6位置为1并输出 , 结果为 75 (0100 1011)System.out.println("\n" + setBitValue((byte) source, 6, (byte) 1));// 将第6位取反并输出, 结果应为75(0100 1011)System.out.println(reverseBitValue((byte) source, 6));// 检查第6位是否为1,结果应为falseSystem.out.println(checkBitValue(source, 6));// 输出为1的位, 结果应为 0 1 3for (byte i = 0; i < 8; i++) {if (checkBitValue(source, i)) {System.out.printf("%d ", i);}}}}

七、附MySQL的支持6种位运算

在这里插入图片描述

八、参考文章

教你巧用mysql位运算解决多选值存储的问题
mysql 条件位运算实现多值存储
Java 一个字段存多个选项 位运算工具类
【架构思想】告别繁琐的多选值存储,MySQL位运算带你飞!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/593125.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

阶段五-JavaWeb综合练习-学生管理系统

一.项目说明 1.前台 (用户使用) 前端,后端 2.后台 (管理员使用) 前端,后端 3.该项目为后台管理系统 项目开发流程: 1.需求分析 1.1 登录功能 用户访问登录页面输入用户名和密码,并且输入验证码。全部输入正确后点击登录&#xff0c;登录成功跳转主页面&#xff1b;登录…

清风数学建模笔记-因子分析

内容&#xff1a;因子分析 概念&#xff1a; 通过分析研究变量间的相关系数矩阵&#xff0c;把这些变量间错综复杂的关系归结成少数几个综合因子&#xff0c;由于归结出的因子个数少于原始变量的个数&#xff0c;但是又包含原始变量的信息&#xff0c;所以这一过程也称之为降…

清风数学建模-数学规划模型

内容&#xff1a;数学规划模型&#xff08;cab aeqbeq lbub&#xff09; 一.题型类型 1.线性规划linprog 2.非线性规划 fmincon 3.整数规划 intlinprog 4.&#xff08;0-1规划&#xff09;&#xff08;特殊的线性整数规划&#xff09;intlinprog 5.多目标规划 linprog 标…

STM32 ESP8266 物联网智能温室大棚 (附源码 PCB 原理图 设计文档)

资料下载: https://download.csdn.net/download/vvoennvv/88680924 一、概述 本系统以STM32F103C8T6单片机为主控芯片&#xff0c;采用相关传感器构建系统硬件电路。其中使用DHT11温湿度传感器对温度和湿度的采集&#xff0c;MQ-7一氧化碳传感器检测CO浓度&#xff0c;GP2Y101…

设计模式:简单工厂模式、工厂方法模式、抽象工厂模式

简单工厂模式、工厂方法模式、抽象工厂模式 1. 为什么需要工厂模式&#xff1f;2. 简单工厂模式2.1. 定义2.2. 代码实现2.3. 优点2.4. 缺点2.5. 适用场景 3. 工厂方法模式3.1. 有了简单工厂模式为什么还需要有工厂方法模式&#xff1f;3.2. 定义3.3. 代码实现3.4. 主要优点3.5.…

深入数组扩展应用

一、字符串反转 例如&#xff1a;‘123abc’----->‘cba321’ 字符串方法实现: var str 123abcvar reversFn function(str) {var newStr for (var i str.length - 1; i > 0; i--) {newStr str[i]}return newStr }console.log(reversFn(str));数组方法实现&#xf…

Elasticsearch:如何使用 Elasticsearch 进行排序

虽然你在唱这首歌时可能会想象圣诞老人&#xff0c;但欧洲民间传说&#xff0c;尤其是阿尔卑斯地区的民间传说&#xff0c;有两个传奇人物圣尼古拉斯和坎普斯。 象征着慷慨和善良的圣尼古拉斯&#xff0c;在 12 月 6 日 为乖巧的孩子们带来礼物和欢乐&#xff01; 相比之下&…

【C语言】作用域 和 生命周期

&#x1f6a9; WRITE IN FRONT &#x1f6a9; &#x1f50e; 介绍&#xff1a;"謓泽"正在路上朝着"攻城狮"方向"前进四" &#x1f50e;&#x1f3c5; 荣誉&#xff1a;2021|2022年度博客之星物联网与嵌入式开发TOP5|TOP4、2021|2222年获评…

计算机网络--作业

作业一 1、比较电路交换、报文交换和分组报文交换优缺点 电路交换 电路交换是以电路连接为目的的交换方式&#xff0c;通信之前要在通信双方之间建立一条被双方独占的物理通道&#xff08;由通信双方之间的交换设备和链路逐段连接而成&#xff09;。 优点&#xff1a; ①由于…

实战SRC | api接口未授权 + 越权漏洞

本文由掌控安全学院 - zxl2605 投稿 一次在fofa上通过学习的fofa语句进行查询&#xff0c;无意中查询到了一个网址 其登录界面如下&#xff1a; 使用浏览器的F12打开开发者工具&#xff0c;查看JS寻找接口&#xff1a; 从JS代码中查询到一处接口如下&#xff1a; 发现是以p…

bilibili深入理解计算机系统笔记(3):使用C语言实现静态链接器

本文是2022年的项目笔记&#xff0c;2024年1月1日整理文件的时候发现之&#xff0c;还是决定发布出来。 Github链接&#xff1a;https://github.com/shizhengLi/csapp_bilibili 文章目录 可执行链接文件(ELF)ELF headerSection header符号表symtab二进制数如何和symtab结构成员…

ELK+kafka+filebeat企业内部日志分析系统搭建

看上面的拓扑图&#xff0c;我们至少准备七台机器进行下面的实验项目。 机器主要作用分布如下: 三台安装elasticsearch来搭建ES集群实现高可用&#xff0c;其他机器就依次安装filebeat,kafka,logstash和kibana软件 一、部署elasticsearch来搭建ES集群 1.安装jdk 由于ES运行…

C语言数组习题

1.数组遍历 #include <stdio.h>int main(){int i,a[10];for(i0;i<9;i) //对数组元素a[0]~a[9]赋值 a[i]i;for(i9;i>0;i--) //输出a[9]~a[0]共10个数组元素 printf("%d ",a[i]);printf("\n");return 0;} 运行结果&#xff1a; 2.数组应用&a…

atoi函数的模拟实现

这里强力推荐一篇文章 http://t.csdnimg.cn/kWuAm 详细解析了atoi函数以及其模拟实现&#xff0c;我这里就不说了。 这里作者先把自己模拟的代码给大家看一下。 int add(char* arr) {char* arr2 arr;while (*arr!-48){arr;}arr--;int sum 0;int n 0;while (arr ! (arr2-…

如何构建高效测试体系?掌握5大自动化测试模式就够了

软件开发过程中&#xff0c;高效的自动化测试体系是提升测试效率、保证产品质量关键&#xff0c;一个全面的测试体系涵盖多个维度&#xff0c;从功能性到用户界面&#xff0c;再到性能和安全性。 每个维度均采用不同的测试模式来满足特定的需求和解决特别的挑战&#xff0c;本…

快速打通 Vue 3(三):Vue3 中的 watch 监听器与新特性

很激动进入了 Vue 3 的学习&#xff0c;作为一个已经上线了三年多的框架&#xff0c;很多项目都开始使用 Vue 3 来编写了 这一组文章主要聚焦于 Vue 3 的新技术和新特性 如果想要学习基础的 Vue 语法可以看我专栏中的其他博客 Vue&#xff08;一&#xff09;&#xff1a;Vue 入…

为什么国产操作系统是基于linux研发的呢?

为什么国产操作系统是基于linux研发的呢&#xff1f; 在开始前我有一些资料&#xff0c;是我根据自己从业十年经验&#xff0c;熬夜搞了几个通宵&#xff0c;精心整理了一份「Linux的资料从专业入门到高级教程工具包」&#xff0c;点个关注&#xff0c;全部无偿共享给大家&…

2023年AIGC发展回顾与展望

2023年是人工智能内容生成&#xff08;AIGC&#xff09;技术飞速发展的一年。从年初ChatGPT一炮打响&#xff0c;大家纷纷加入到大模型研究之中。期间Midjourney和Stable Diffusion AI绘画技术持续火热&#xff0c;基于AIGC类的应用也如雨后春笋般遍地开花。万众瞩目的OpenAI G…

1.1 理解大数据(2)

小肥柴的Hadoop之旅 1.1 理解大数据&#xff08;2&#xff09; 目录1.1 理解大数据1.1.3 大数据概述1.1.4 更多思考 参考文献和资料 目录 1.1 理解大数据 1.1.3 大数据概述 step_0 大数据定义 【《大数据算法设计分析》】&#xff1a; 通常来讲大数据&#xff08;Big Data&am…

生态系统服务构建生态安全格局中的实践技术应用

生态安全是指生态系统的健康和完整情况。生态安全的内涵可以归纳为&#xff1a;一&#xff0c;保持生态系统活力和内外部组分、结构的稳定与持续性&#xff1b;二&#xff0c;维持生态系统生态功能的完整性&#xff1b;三&#xff0c;面临外来不利因素时&#xff0c;生态系统具…