sql列中数据通过逗号分割的集合,按需求剔除部分值

发布于:2025-06-10 ⋅ 阅读:(39) ⋅ 点赞:(0)

前置

不会REGEXP 方法的需要在这里学习一下下
记sql字段逗号分隔,通过list查询

功能点

现有一个表格中一列存储的是标签的集合,通过逗号分割
入下:
在这里插入图片描述
其中tag_ids是逗号分割的标签,现在需要删除标签组中的一些标签,因此,该关联表中需要同步删除掉标签的id,例如删除标签组的[1,5,7],如何处理后,保存id是1 的数据的tag_ids保留数据为[2,3,4,6]

分析

首先,要将tag_ids 的“,”进行补全,然后就可以先通过 “1,”、“5,”、“7,”进行字符串截取,然后再将添加的“,” 剔除掉
引入函数TRIM

TRIM([LEADING | TRAILING | BOTH] [trim_character] FROM string)

LEADING:仅去除字符串开头的指定字符。
TRAILING:仅去除字符串结尾的指定字符。
BOTH:去除字符串开头和结尾的指定字符(默认行为)。
trim_character:要移除的字符。如果省略,则默认为空格。
string:要处理的字符串。
例如:

TRIM(BOTH ',' FROM CONCAT(',', tag_ids, ','))

我们插入的两个逗号通过trim删除掉了
在这里插入图片描述
ok,接下来就是如何剔除[1,5,7]了,我们需要引入函数REPLACE

REPLACE(string, old_substring, new_substring)

string:要处理的原始字符串。
old_substring:要被替换的子字符串。
new_substring:用于替换的子字符串。如果 new_substring 是一个空字符串,那么 old_substring 将被删除。

 REPLACE(CONCAT(',', tag_ids, ','), ",1,", ",")

在这里插入图片描述
如上图,我们已经剔除“1”了,如何剔除 5,7,在这里提供一个方法,不代表这个发方法是最优方法
使用REPLACE进行嵌套

SELECT TRIM(BOTH ',' FROM REPLACE(
			REPLACE(
					REPLACE(
							CONCAT(',', tag_ids, ','), 
							',1,', ','
					), ',5,', ','
			), 
			',7,', ','
		)) new_str FROM DUAL

在这里插入图片描述
由此,这个方法是可行的,那么开始使用xml的传参进行写

实现

 <update id="changCustomerTag">
     update scrm_customer c
     set c.tag_ids = TRIM(BOTH ',' FROM
     <foreach collection="tagIds">
         REPLACE(
     </foreach>
     CONCAT(',', c.tag_ids, ','),
     <foreach collection="tagIds" item="tagId" separator="),">
         concat(',', #{tagId},','), ','
     </foreach>
         ))
     where c.tag_ids regexp  concat('(^|,)',
         <foreach collection="tagIds"  item="tagId" open="(" separator="|" close=")">
             #{tagId}
         </foreach>
         , '(,|$)')
 </update>
   void changCustomerTag(@Param("tagIds") List<Long> tagIds);

如果你的项目不支持xml,也可以写存储过程

DROP PROCEDURE IF EXISTS ChangeCustomerTag;
CREATE PROCEDURE ChangeCustomerTag(IN tagIds VARCHAR(255))
BEGIN
    DECLARE done INT DEFAULT FALSE;
    DECLARE tagId VARCHAR(255);
    DECLARE tagIdList TEXT DEFAULT '';
    DECLARE tempList TEXT DEFAULT '';
		-- 创建游标
		DECLARE cur CURSOR FOR SELECT * FROM (
		-- WITH RECURSIVE 创建数字类型,根据逗号数量得出数据数量
		WITH RECURSIVE numbers AS (SELECT 1 AS n UNION ALL SELECT n + 1 FROM numbers WHERE n < (LENGTH(tagIds) - LENGTH(REPLACE(tagIds, ',', ''))) + 1)
		-- 得出传入的每一个值
		SELECT SUBSTRING_INDEX(SUBSTRING_INDEX( tagIds , ',',n), ',', -1) tagId FROM numbers) t;
    DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = TRUE;
	
    OPEN cur;
 
    read_loop: LOOP
        FETCH cur INTO tagId;
				
        IF done THEN
            LEAVE read_loop;
        END IF;
				
        IF tempList = '' THEN
            SET tempList = CONCAT('CONCAT(\','', c.tag_ids, \',\')');
        END IF;
				-- 拼接sql
				SET tagIdList = CONCAT( 'REPLACE(', IF(tagIdList = '',tempList,tagIdList), ', CONCAT( \',\',', tagId, ',\',\' ),\',\')');
    END LOOP;
 
    CLOSE cur;
 
    SET @sql = CONCAT('UPDATE scrm_customer c
                      SET c.tag_ids = TRIM(BOTH \',\' FROM ', tagIdList, ')
                      WHERE c.tag_ids REGEXP CONCAT(\'(^|)\', (', REPLACE(tagIds, ',', '|'), '), \'(,|$)\')');

		-- 动态创建sql语句
    PREPARE stmt FROM @sql;
		-- 执行sql语句
    EXECUTE stmt;
		-- 释放语句
    DEALLOCATE PREPARE stmt;
END;
CALL ChangeCustomerTag('1,5,7');

原数据
在这里插入图片描述
执行后数据
在这里插入图片描述

最后

主要是自己懒得弄分表,就这样凑合用吧。
有更佳方案或者新奇想法的同学可以分享一下。
该文章为原创,未经允许禁止转载,谢谢


网站公告

今日签到

点亮在社区的每一天
去签到