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

news2024/11/20 8:33:06

一、多值存储

  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)
     */
    @Test
    public void testAnd(){
        //查一下周一和周四都值班的人;
        //周一:1;周四:8
        Integer[] 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)
     */
    @Test
    public void testOr() {
        //查询包含周日or周三的
        //周日:64;周四:8
        Integer[] weekArr={64,8};
        List<Integer> weekList = Arrays.asList(weekArr);
        List<MybatisxDutyInfo> mybatisxDutyInfos = mybatisxDutyInfoService.listByBinOr(weekList);
        System.out.println("周日or周三值班的人:"+ JSON.toJSONString(mybatisxDutyInfos));
    }
@Override
    public 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)
     */
    @Test
    public void testNotIs() {
        //查询不包含周二的
        //周二:2
        Integer 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')
     */
    @Test
    public void testUpdateDuty() {
        //周一周三周四
        Integer[] weekArr={1,8,16};
        List<Integer> weekList = Arrays.asList(weekArr);
        mybatisxDutyInfoService.updateDuty(weekList,"张三");
    }
@Override
    public 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 1011
        for (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,结果应为false
        System.out.println(checkBitValue(source, 6));

        // 输出为1的位, 结果应为 0 1 3
        for (byte i = 0; i < 8; i++) {
            if (checkBitValue(source, i)) {
                System.out.printf("%d ", i);
            }
        }

    }

}

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

在这里插入图片描述

八、参考文章

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

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

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

相关文章

ASP.NET Core AOT

Native AOT 最初在 .NET 7 中引入&#xff0c;在即将发布的 .NET 8 版本中可以与 ASP.NET Core 一起使用。在这篇文章中&#xff0c;我们从总体角度审视其优点和缺点&#xff0c;并进行测量以量化不同平台上的改进。 源代码&#xff1a;https://download.csdn.net/download/he…

MATLAB中xcorr函数用法

目录 语法 说明 示例 两个向量的互相关 向量的自相关 归一化的互相关 xcorr函数的功能是返回互相关关系。 语法 r xcorr(x,y) r xcorr(x) r xcorr(___,maxlag) r xcorr(___,scaleopt) [r,lags] xcorr(___) 说明 r xcorr(x,y) 返回两个离散时间序列的互相关。互相…

SpringBoot整合ElasticSearch实现CRUD操作

本文来说下SpringBoot整合ES实现CRUD操作 文章目录 概述项目搭建 概述 SpringBoot支持两种技术和es交互。一种的jest&#xff0c;还有一种就是SpringData-ElasticSearch。根据引入的依赖不同而选择不同的技术。反正作为spring全家桶&#xff0c;目前是以springdata为主流使用技…

uniapp中uview组件丰富的Code 验证码输入框的使用方法

目录 基本使用 #自定义提示语 #保持倒计时 API #Props #Methods #Event 基本使用 通过ref获取组件对象&#xff0c;再执行后面的操作&#xff0c;见下方示例。 通过seconds设置需要倒计的秒数(默认60)通过ref调用组件内部的start方法&#xff0c;开始倒计时通过监听cha…

在 Oracle 数据库表中加载多个数据文件

在本文中&#xff0c;我将展示 SQL 加载器 Unix 脚本实用程序的强大功能&#xff0c;其中 SQL 加载器可以使用自动 shell 脚本加载多个数据文件。这在处理大量数据以及需要将数据从一个系统移动到另一个系统时非常有用。 它适合涉及大量历史数据的迁移项目。那么就不可能为每…

跟着cherno手搓游戏引擎【2】:日志系统spdlog和premake的使用

配置&#xff1a; 日志库文件github&#xff1a; GitHub - gabime/spdlog: Fast C logging library. 新建vendor文件夹 将下载好的spdlog放入 配置YOTOEngine的附加包含目录&#xff1a; 配置Sandbox的附加包含目录&#xff1a; 包装spdlog&#xff1a; 在YOTO文件夹下创建…

ORACLE Primavera P6, Unifier v23.12 系统分享

引言 根据上周的计划&#xff0c;我近日简单制作了一个基于ORACLE Primavera P6 EPPM 以及Unifier 最新版23.12的虚拟机演示环境&#xff0c;里面包括了p6 和 unifier的全套系统服务 此虚拟系统环境仅用于演示、培训和测试目的。如要在生产环境中使用此虚拟机&#xff0c;请您…

计算机毕业设计 SpringBoot的停车场管理系统 Javaweb项目 Java实战项目 前后端分离 文档报告 代码讲解 安装调试

&#x1f34a;作者&#xff1a;计算机编程-吉哥 &#x1f34a;简介&#xff1a;专业从事JavaWeb程序开发&#xff0c;微信小程序开发&#xff0c;定制化项目、 源码、代码讲解、文档撰写、ppt制作。做自己喜欢的事&#xff0c;生活就是快乐的。 &#x1f34a;心愿&#xff1a;点…

自定义指令:让 Vue 开发更有趣(下)

&#x1f90d; 前端开发工程师&#xff08;主业&#xff09;、技术博主&#xff08;副业&#xff09;、已过CET6 &#x1f368; 阿珊和她的猫_CSDN个人主页 &#x1f560; 牛客高级专题作者、在牛客打造高质量专栏《前端面试必备》 &#x1f35a; 蓝桥云课签约作者、已在蓝桥云…

SkyWalking实战与设置警告

日升时奋斗&#xff0c;日落时自省 目录 1、简述 2、Skywalking优越性 2.1、相同产品分析 2.2、Skywalking组成 2.3、Skywalking本质 3、Skywalking服务安装与启动 3.1、ES安装并启动 3.1.2、删除环境变量 3.1.3、预启动ES 3.1.4、关闭HTTPS认证 3.1.5、关闭登录授…

Go语言基础简单了解

文章目录 前言关于Go学习流程 基础语法注释变量常量数据类型运算符fmt库 流程控制if、switch、selectfor、break、continue遍历String 函数值传递和引用传递deferinit匿名、回调、闭包函数 数组和切片Map结构体自定义数据类型接口协程和channel线程锁异常处理泛型文件读取文件写…

MCS-51存储器的特点

目录 1.MCS-51存储器的结构 2.片内数据存储器 (1)片内数据存储器低128B (2) 片外数据存储器高128B 2.片内数据存储器高128B 3.片内程序存储器 1.MCS-51存储器的结构 如图所示&#xff0c;MCS-51 的存储器在物理结构上分成四个存储空间:片内程序存储器、片外程序存储器、…

Clojure 实战(4):编写 Hadoop MapReduce 脚本

Hadoop简介 众所周知&#xff0c;我们已经进入了大数据时代&#xff0c;每天都有PB级的数据需要处理、分析&#xff0c;从中提取出有用的信息。Hadoop就是这一时代背景下的产物。它是Apache基金会下的开源项目&#xff0c;受Google两篇论文的启发&#xff0c;采用分布式的文件…

算法巡练day03Leetcode203移除链表元素707设计链表206反转链表

今日学习的文章视频链接 https://www.bilibili.com/video/BV1nB4y1i7eL/?vd_source8272bd48fee17396a4a1746c256ab0ae https://programmercarl.com/0707.%E8%AE%BE%E8%AE%A1%E9%93%BE%E8%A1%A8.html#%E7%AE%97%E6%B3%95%E5%85%AC%E5%BC%80%E8%AF%BE 链表理论基础 见我的博…

擎创技术流 |如何使用eBPF监控NAT转换

一、NAT简介 Linux NAT&#xff08;Network Address Translation&#xff09;转换是一种网络技术&#xff0c;用于将一个或多个私有网络内的IP地址转换为一个公共的IP地址&#xff0c;以便与互联网通信。 图源于网络 在k8s业务场景中&#xff0c;业务组件之间的关系十分复杂. …

uni-app 前后端调用实例 基于Springboot 上拉分页实现

锋哥原创的uni-app视频教程&#xff1a; 2023版uniapp从入门到上天视频教程(Java后端无废话版)&#xff0c;火爆更新中..._哔哩哔哩_bilibili2023版uniapp从入门到上天视频教程(Java后端无废话版)&#xff0c;火爆更新中...共计23条视频&#xff0c;包括&#xff1a;第1讲 uni…

音视频通信

文章目录 一、音视频通信流程二、流媒体协议1、RTSP2、RTMP3、HLS4、WebRTC 一、音视频通信流程 音视频通信完整流程有如下几个环节&#xff1a;采集、编码、前后处理、传输、解码、缓冲、渲染等。 每一个细分环节&#xff0c;还有更细分的技术模块。比如&#xff0c;前后处…

【数据结构】二叉搜索(查找/排序)树

一、二叉搜索树基本概念 1、定义 二叉搜索树&#xff0c;又称为二叉排序树&#xff0c;二叉查找树&#xff0c;它满足如下四点性质&#xff1a; 1&#xff09;空树是二叉搜索树&#xff1b; 2&#xff09;若它的左子树不为空&#xff0c;则左子树上所有结点的值均小于它根结…

使用宝塔在Linux面板搭建网站,并实现公网远程访问

文章目录 前言1. 环境安装2. 安装cpolar内网穿透3. 内网穿透4. 固定http地址5. 配置二级子域名6. 创建一个测试页面 前言 宝塔面板作为简单好用的服务器运维管理面板&#xff0c;它支持Linux/Windows系统&#xff0c;我们可用它来一键配置LAMP/LNMP环境、网站、数据库、FTP等&…

STL map容器与pair类模板(解决扫雷问题)

CSTL之Map容器 - 数据结构教程 - C语言网 (dotcpp.com)https://www.dotcpp.com/course/118CSTL之Pair类模板 - 数据结构教程 - C语言网 (dotcpp.com)https://www.dotcpp.com/course/119 刷到一个扫雷的题目&#xff0c;之前没有玩怎么过扫雷&#xff0c;于是我就去玩了玩…