• Mysql逗号拼接字符串的关联查询及统计


    背景:

    数据库中逗号拼接的字符串,想展示其完整拼接名称或者按其值统计处理,怎么做?
    FIND_IN_SET函数和GROUP_CONCAT函数你会用吗?

    一、查询问题

    eg两张表 t_conclusion_detail(拜访信息表) 和 t_conclusion_info(拜访结论表)
    t_conclusion_detail:

    iduserNameconclusionIds
    781918060586991616梦琪1,3
    781986564770103296西施3
    781989822074978304火舞2,3,4

    t_conclusion_info:

    conclusionIdconclusionName
    1已成交
    2暂无兴趣
    3需要跟进
    4沟通顺利

    想要的效果:

    iduserNameconclusionIdsconclusionNameStr
    781918060586991616梦琪1,3已成交,需要跟进
    781986564770103296西施3需要跟进
    781989822074978304火舞2,3,4暂无兴趣,需要跟进,沟通顺利

    思考🤔:
    一般这种情况两种方案:要么代码层面处理,要么数据库层面处理
    1、方案一( 代码层面):先查拜访信息表,将数据返回到服务器,在代码里进行切割,然后再去拜访结论表里面去查询对应的名称,返回到程序进行处理拼接。造成频繁访问数据库,或需要批量查回再匹配处理,这样做虽然很简单也很好理解但是效率太低。
    2、方案二(数据库):以mysql为例,使用FIND_IN_SET函数和GROUP_CONCAT函数进行查询,但是数据量特别大时可能不友好,利用不上索引等

    SELECT 
    s.id,s.user_name userName,s.conclusion_ids conclusionIds,
    (SELECT GROUP_CONCAT(user_name) 
    FROM t_conclusion_info tr 
    WHERE FIND_IN_SET(tr.conclusion_id,(SELECT conclusion_ids FROM t_conclusion_detail WHERE id=s.id))) AS conclusionNameStr
    FROM t_conclusion_detail s 
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    tip:如果数据量特别大建议还是设计时不要逗号拼接设计,改成多表联查,或者使用代码层面处理

    二、统计问题

    还是上述两张表,想要的效果是每个结论出现频次的统计,即统计逗号拼接的字符串中内容
    伪代码,具体根据情况拼接业务sql:

    SELECT
    sum(case when find_in_set('1',conclusion_ids)>0  then 1 else 0 end) one,
    sum(case when find_in_set('2',conclusion_ids) >0 then 1 else 0 end) two,
    sum(case when find_in_set('3',conclusion_ids) >0 then 1 else 0 end) three,
    sum(case when find_in_set('4',conclusion_ids) >0 then 1 else 0 end) four
    from t_conclusion_detail
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    结果:

    onetwothreefour
    1131

    三、效率问题

    思考🤔: 模拟插入20万数据,查看find_in_set效率问题:

    CREATE TABLE `t_conclusion_detail` (
       `id` bigint unsigned NOT NULL AUTO_INCREMENT COMMENT '主键',
       `user_name` varchar(32) COMMENT '姓名',
       `conclusion_ids` varchar(32) COMMENT '拜访结论(多个结论逗号分隔)'
      PRIMARY KEY (`id`)    
    ) ENGINE=InnoDB AUTO_INCREMENT=1 COMMENT='拜访记录表'; 
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    DROP PROCEDURE IF EXISTS `t_conclusion_detail_memory`
    
    DELIMITER //
    CREATE PROCEDURE `t_conclusion_detail_memory`(IN n INT)
    BEGIN
        DECLARE i INT DEFAULT 1;
        DECLARE id INT DEFAULT 1;
        DECLARE num1 INT DEFAULT 1;
        DECLARE num2 INT DEFAULT 1;
        DECLARE num3 INT DEFAULT 1;
        WHILE i < n DO
            SET id = i;
            SET num1 = FLOOR(0 + RAND()*6);
            SET num2 = FLOOR(0 + RAND()*6);
            SET num3 = FLOOR(0 + RAND()*6);
            INSERT INTO `t_conclusion_detail` VALUES (id, 'test', concat(num1,',',num2,',',num3), );
            SET i = i + 1;
        END WHILE;
    END //
    DELIMITER ;  -- 改回默认的 MySQL delimiter:';'
    
    CALL t_conclusion_detail_memory(200000); 
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23

    经实验,20w数据时相关查询最慢2s左右,可接受范围。

  • 相关阅读:
    JSP在Scriptlet中编写java代码的形式
    AIGC创作系统ChatGPT网站系统源码,支持最新GPT-4-Turbo模型
    [安卓android毕业设计]精品基于Uniapp+SSM实现的校园心理健康APP[源码]
    解决LaTex中插入Visio画图有多余边框的问题
    开设自己的网站系类01购买服务器
    说说你对Vue的keep-alive的理解
    技术分享|新代币标准的讨论
    Vue + Element ui 实现动态表单,包括新增行/删除行/动态表单验证/提交功能
    复制带随机指针的链表
    iapp源码集锦
  • 原文地址:https://blog.csdn.net/weixin_47061482/article/details/127690069