前置
不会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');
原数据
执行后数据
最后
主要是自己懒得弄分表,就这样凑合用吧。
有更佳方案或者新奇想法的同学可以分享一下。
该文章为原创,未经允许禁止转载,谢谢