mysql字段userid逗号分开保存按userid查询

2023-05-16

我的sql水平一般,仅是一个笔记。无法保存是最优解。仅供参考。

场景

有一张消息表,其中有一个收信人字段中把多个用户以,分隔保存信息。我需要根据userid来查询信息。为了方便理解,我减化一下表结构。我的表结构如下:

message_idreceiversendermessagecreate_time
1user1,user2systemhello2022-06-30 16:30:12
2user1,user3systemworld2022-06-30 16:31:19
3user3,user4,user5user1java2022-06-30 16:31:22
4user7,user8user2neovim2022-06-30 16:31:53
5itkey,lxyoucansystemitkey2022-06-30 16:32:17
6user,user11goodvery2022-06-30 16:38:18

表结构

create table t_message
(
    message_id     bigint auto_increment comment '消息ID'
        primary key,
    receiver       varchar(4000)    null comment '收件人',
    sender         varchar(200)     not null comment '发件人',
    message        varchar(4000)    not null comment '消息内容',
    create_time    datetime         null comment '创建时间'
)
    comment '消息中心';

数据

INSERT INTO t_message (message_id, receiver, sender, message, create_time) VALUES (1, 'user1,user2', 'system', 'hello', '2022-06-30 16:30:12');
INSERT INTO t_message (message_id, receiver, sender, message, create_time) VALUES (2, 'user1,user3', 'system', 'world', '2022-06-30 16:31:19');
INSERT INTO t_message (message_id, receiver, sender, message, create_time) VALUES (3, 'user3,user4,user5', 'user1', 'java', '2022-06-30 16:31:22');
INSERT INTO t_message (message_id, receiver, sender, message, create_time) VALUES (4, 'user7,user8', 'user2', 'neovim', '2022-06-30 16:31:53');
INSERT INTO t_message (message_id, receiver, sender, message, create_time) VALUES (5, 'itkey,lxyoucan', 'system', 'itkey', '2022-06-30 16:32:17');
INSERT INTO t_message (message_id, receiver, sender, message, create_time) VALUES (6, 'user,user11', 'good', 'very', '2022-06-30 16:38:18');

实践

[错误的示范]like模糊匹配

首先我第一个思路想到的是使用like语句进行模糊查询。看似简单易用,但是会有bug。

比如查询user3

select * from t_message where receiver like '%user3%';
message_idreceiversendermessagecreate_time
2user1,user3systemworld2022-06-30 16:31:19
3user3,user4,user5user1java2022-06-30 16:31:22

没有任何问题,但如果我要查询user用户的数据呢?

select * from t_message where receiver like '%user%';
message_idreceiversendermessagecreate_time
1user1,user2systemhello2022-06-30 16:30:12
2user1,user3systemworld2022-06-30 16:31:19
3user3,user4,user5user1java2022-06-30 16:31:22
4user7,user8user2neovim2022-06-30 16:31:53
6user,user11goodvery2022-06-30 16:38:18

发现此时查询的数据就不准备了,userid越是短的,查的越不精确。

可行的办法

首先说明,可能不是最好的解决办法,仅供参考。如果您有更好的办法,欢迎评论区交流。

help_topic

开始之前我们先简答的了解一下help_topic,主要是用来把一行变成多行的。

select substring_index(substring_index('82,83,84,85,86', ',', help_topic_id + 1), ',', -1) as Id
from mysql.help_topic
where help_topic_id < (length('82,83,84,85,86') - length(replace('82,83,84,85,86', ',', '')) + 1);

执行结果:

Id
82
83
84
85
86

解析

乍一看比较绕,我尽量写详细一些。

  1. substring_index的作用:取得目标字符串左侧第n个分割符左侧的部分,n为负时返回右侧第n个的右部分。

  2. help_topic 是数据库mysql的一个表,该表提供查询帮助主题给定关键字的详细内容(详细帮助信息)
    表字段含义:

    • help_topic_id:帮助主题详细信息在表记录中对应的ID
    • name:帮助主题给定的关键字名称。
    • help_category_id:帮助主题类别ID,与help_category表中的help_category_id字段值相等。
    • description:帮助主题的详细信息(这里就是我们通常查询帮助信息真正想看的内容,例如:告诉我们某某语句如何使用的语法与注意事项等)。
    • example:帮助主题的示例信息(告诉我们语句如何使用的示例)。
    • url:该帮助主题对应在MySQL官方在线手册中的URL链接地址。

ps:这条sql语句其实跟help_topic表没有什么关系,仅仅是借用了help_topic表的help_topic_id的值为(0,1,2,…),因此在本数据库中建立一个仅含ID字段的表进行关联,同样可以实现转多行效果

where 查询条件部分

(length('82,83,84,85,86') - length(replace('82,83,84,85,86', ',', '')) + 1)

看着很长,其实就是为了计算,分隔的部分信息数量。也就是,的数量+1。其实最终目标也只是得到了一个0,1,2,3,4的列表。有这样信息,就可以用来截取字符串了。

可以把这个sql一段一段执行,直至完全理解。

最终实现

SELECT
    message_id,
    substring_index( substring_index( msg.receiver, ',', topic.help_topic_id + 1 ), ',',- 1 ) AS receiver,
    sender,
    message,
    create_time
FROM
    t_message msg
        JOIN mysql.help_topic topic ON topic.help_topic_id < ( length( msg.receiver ) - length( REPLACE ( msg.receiver, ',', '' ) ) + 1 );

查询结果如下:

message_idreceiversendermessagecreate_time
1user1systemhello2022-06-30 16:30:12
1user2systemhello2022-06-30 16:30:12
2user1systemworld2022-06-30 16:31:19
2user3systemworld2022-06-30 16:31:19
3user3user1java2022-06-30 16:31:22
3user4user1java2022-06-30 16:31:22
3user5user1java2022-06-30 16:31:22
4user7user2neovim2022-06-30 16:31:53
4user8user2neovim2022-06-30 16:31:53
5itkeysystemitkey2022-06-30 16:32:17
5lxyoucansystemitkey2022-06-30 16:32:17
6usergoodvery2022-06-30 16:38:18
6user11goodvery2022-06-30 16:38:18

得到这个表以后,查询就比较简单了。我比较担心的是,性能可能不会特别的高。
这时候我们还按user来查询,写法如下:

select * from (
                  SELECT message_id,
                         substring_index(substring_index(msg.receiver, ',', topic.help_topic_id + 1), ',',
                                         - 1) AS receiver,
                         sender,
                         message,
                         create_time
                  FROM t_message msg
                           JOIN mysql.help_topic topic ON topic.help_topic_id <
                                                          (length(msg.receiver) - length(REPLACE(msg.receiver, ',', '')) + 1)
              ) as tmsg where tmsg.receiver='user';
message_idreceiversendermessagecreate_time
6usergoodvery2022-06-30 16:38:18

这次的查询结果就是正确的了。

减少子查询的使用,可以写成如下:

SELECT
    message_id,
    sender,
    message,
    create_time
FROM
    t_message msg
        JOIN mysql.help_topic topic ON topic.help_topic_id < ( length( msg.receiver ) - length( REPLACE ( msg.receiver, ',', '' ) ) + 1 )
where substring_index( substring_index( msg.receiver, ',', topic.help_topic_id + 1 ), ',',- 1 ) = 'user';

查询结果:

message_idsendermessagecreate_time
6goodvery2022-06-30 16:38:18

总结

最终方案的准确性应该是没有问题了,但是性能方面还是有优化的空间的。

参考

  • https://blog.csdn.net/lshxuexi/article/details/113571795
  • https://blog.csdn.net/hfsaini/article/details/86477371
  • https://www.jianshu.com/p/2c17b3360059
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

mysql字段userid逗号分开保存按userid查询 的相关文章

随机推荐

  • VirtualBox调整分分辨率

    以前在windows或者macOS基本都是使用vmware来玩虚拟机的 到linux环境 xff0c 想体验一下VirtualBox 结果用的时间发现分辨率都是调不出来 记录一下我的操作方法 环境 宿主机 xff1a archlinux 4
  • VirtualBox宿主机复制粘贴时有时无

    现象 首先我已经安装了增强功能 xff0c 共享剪切板选择的也是双向 虚拟机刚开机剪切板功能是正常的 可以双向复制 但是用了一段时间以后 xff0c 就会发现从宿主机得到到虚拟机就不行了 但是可以从虚拟机复制到宿主机 环境 我的宿主机是 a
  • HBuilderX运行微信小程序不报错也打不开

    我主用的是linux操作系统 xff0c 因为要开发微信小程序 所以在虚拟机中安装了一个windows7系统 环境 虚拟机中的windows7 HbuilderX 43 微信开发者工具 现象 使用HbuilderX开发uni app并想在微
  • Virtualbox虚拟机与主机相互访问

    刚从vmware切换到Virtualbox有些地方还是不太熟悉 网络连接这块就被卡了一下 xff0c 后来发现其实很简单 xff0c 是我想多了 环境 主机 xff1a archlinux 虚拟机 xff1a windows 10 软件版本
  • maven打包报内存不足,配置maven vm options

    服务器上内存所剩余不多了 xff0c 用mvn打包报内存不足 解决办法就要把vm options中内存设置小一些 mvn jvm config文件 xff1a 从 Maven 3 3 1 43 开始 xff0c 您可以通过 maven pr
  • archlinux滚动更新导致virtualbox虚拟机无法启动

    今天遇到一个奇怪的问题 xff0c 滚动更新以后 xff0c pacman Syyu 虚拟机无法正常启动了 虚拟机启动以后一直显示Starting virtual machine 并且卡在20 不动了 原因分析 我怀疑是更新系统后 xff0
  • 设计模式之【工厂模式】,创建对象原来有这么多玩法

    文章目录 一 什么是工厂模式1 工厂模式的意义2 什么时候应该用工厂模式 二 简单工厂模式1 实例 xff08 1 xff09 使用简单工厂进行优化 xff08 2 xff09 静态工厂 xff08 3 xff09 使用map来去除if x
  • archlinux安装node.js长期支持版本

    默认archlinux安装的node js版本是18 我今天在遇到项目时报错了 xff0c 项目中用到一个组件不支持18 那么如果安装 低版本的Node呢 xff1f 先在软件仓库中搜索一下 xff1a pacman Ss span cla
  • windows开机启动目录

    设置windows开机启动有很多种方法 xff0c 最简单的方法恐怕就是把快捷方式放到启动目录吧 windows开机启动目录 按下 win 43 R 打开运行输入 xff1a shell span class token operator
  • linux 灰度显示grayscale

    之前我在使用macOS的时候 xff0c 非常喜欢使用灰度显示界面 到底是什么原因让我有这么 变态 的需求 下面听听我的故事 xff0c 当时不重要 xff0c 可以跳过 是这样的 xff0c 因为我是程序员 xff0c 算上电脑 43 手
  • charles iOS手机抓包

    iOS手机如何抓包 下载charles https www charlesproxy com latest release download do 注册码 Registered Name span class token builtin c
  • redis cli笔记

    此篇为人个笔记 xff0c 基本是个人常用命令 xff0c 仅供参考 基础操作 redis cli redis span class token number 127 0 span 0 1 637 span class token oper
  • Jsoup通过curl Request设置header

    使用Charles时发现它有一个功能非常的方便 Copy cURL Request菜单 可以把请求中的header信息自动拼接成curl的参数 其实有很多的软件都具备这样的功能 那么如何把这些header信息直接 放到Jsoup的heade
  • 【Java题】用户数据中的身高体重收集

    题目要求 用户数据中的身高体重收集 应用程序中用户数据收集 xff0c 非常重要 xff0c 是大数据重要来源之一 在某APP场景中收集用户的身高体重数据 xff0c 身高单位 米 xff0c 体重单位kg xff0c 要求用户输入的任何数
  • archlinux i3wm通知管理

    通知管理 Dunst 是大多数桌面环境提供的通知守护程序的轻量级替代品 它非常可定制 xff0c 不依赖于任何工具包 xff0c 因此适合那些我们都喜欢定制到完美的以窗口管理器为中心的设置 官网如下 xff1a https dunst pr
  • i3wm 获取window class

    在i3wm中如果你想让一个程序固定在某个workspace中打开可以如下设置 span class token comment 打开virtual box直接进入第10个桌面 span assign span class token pun
  • xrandr修改分辨率与刷新率

    查询当前显示器信息 直接运行xrandr即可 我的执行结果如下 xff0c 信息过多 xff0c 我则把关键部分放出来 xff1a itkey 64 vivobook screenlayout xrandr span class token
  • 设计模式之【适配器模式】,两个人之间确实需要月老的搭线~

    文章目录 一 什么是适配器模式1 适配器模式使用场景2 代理 桥接 装饰器 适配器 4 种设计模式的区别3 适配器模式结构 二 类适配器1 实例 三 对象适配器1 实例 四 接口适配器1 实例 五 源码中的应用 一 什么是适配器模式 适配器
  • linux黑客帝国cmatrix

    装X神器 xff0c 黑客帝国 xff01 xff01 xff01 安装方法 我这里以archlinux为例 span class token function sudo span pacman S cmatrix 效果演示
  • mysql字段userid逗号分开保存按userid查询

    我的sql水平一般 xff0c 仅是一个笔记 无法保存是最优解 仅供参考 场景 有一张消息表 xff0c 其中有一个收信人字段中把多个用户以 分隔保存信息 我需要根据userid来查询信息 为了方便理解 xff0c 我减化一下表结构 我的表