使用到数据库自带的mysql.help_topic表来属性拆分,help_topic表就是实现行转列功能
列转行
SELECT
SUBSTRING_INDEX(
SUBSTRING_INDEX('1,2,3,4,5',',',help_topic_id + 1),',' ,- 1) lzh
FROM
mysql.help_topic
WHERE
help_topic_id < (LENGTH('1,2,3,4,5')) - LENGTH(REPLACE ('1,2,3,4,5', ',', '')) + 1;
或
SELECT SUBSTRING_INDEX(SUBSTRING_INDEX('7654,7698,7782,7788',',',help_topic_id+1),',',-1) AS num
FROM mysql.help_topic
WHERE help_topic_id < LENGTH('7654,7698,7782,7788')-LENGTH(REPLACE('7654,7698,7782,7788',',',''))+1
字符串拆分
substring_index(str,delim,count)
参数解说 解释
str 需要拆分的字符串
delim 分隔符,通过某字符进行拆分
count 当 count 为正数,取第 n 个分隔符之前的所有字符; 当 count 为负数,取倒数第 n 个分隔符之后的所有字符。
# 获取第2个以逗号为分隔符之前的所有字符。
SELECT SUBSTRING_INDEX('1,2,3,4',',',2);
# 获取最后一个到倒数第2个以逗号分隔符之后的所有字符
SELECT SUBSTRING_INDEX('1,2,3,4',',',-2);
# 所以,我们的核心代码中的 -1 ,就是获取以逗号为分隔符的最后一个值;也就是4
替换函数
replace(str,from_str,to_str)
参数名 解释
str 需要进行替换的字符串
from_str 需要被替换的字符串
to_str 需要替换的字符串
# 将分隔符逗号替换为空。
SELECT REPLACE('1,2,3,4',',','');
获取字符串长度
length(str)
参数名 解释
str 需要计算长度的字符串
# 获取 '1,2,3,4' 字符串的长度
SELECT LENGTH('1,2,3,4')
列转行实现解析
需要解析的SQL
SELECT SUBSTRING_INDEX(SUBSTRING_INDEX('1,2,3,4',',',help_topic_id+1),',',-1) AS num
FROM mysql.help_topic
WHERE help_topic_id < LENGTH('1,2,3,4')-LENGTH(REPLACE('1,2,3,4',',',''))+1
此处利用 mysql 库的 help_topic 表的 help_topic_id 来作为变量,因为 help_topic_id 是自增的,当然也可以用其他表的自增字段辅助。
注意,这个辅助表的ID最大长度只有642;如果过长的字符串,可能需要借助其他自增的辅助表(可以是现有表,也可以自己造一个 1,2,3,4 递增的行即可)
- 首先获取最后需被拆分成多少个字符串,利用help_topic_id 来模拟遍历第n个字符串
这一步核心是获取,有多少个分隔符,就有多少个逗号
代码片段:
help_topic_id < LENGTH('1,2,3,4')-LENGTH(REPLACE('1,2,3,4',',',''))+1
因为 help_topic_id是从0开始的,所以会得出 help_topic_id 值为:0~3,共4行数据;
- 根据“,”逗号来拆分字符串,此处利用 SUBSTRING_INDEX(str, delim, count) 函数,最后把结果赋值给 num 字段
代码片段
SUBSTRING_INDEX(SUBSTRING_INDEX('7654,7698,7782,7788',',',help_topic_id+1),',',-1) AS num
第一步:
以”,”逗号为分隔符,根据 help_topic_id 的值来截取第n+1个分隔符之前所有的字符串。 (此处 n+1 是因为help_topic_id 是从0开始算起,而此处需从第1个分隔符开始获取。
SUBSTRING_INDEX('1,2,3,4',',',help_topic_id+1)
eg:
当 help_topic_id = 0时,获取到的字符串 = 1
当 help_topic_id = 1时,获取到的字符串 = 1,2 …(以此类推)
第二步:
以”,”逗号为分隔符,截取倒数第1个分隔符之后的所有字符串。
SUBSTRING_INDEX(SUBSTRING_INDEX('1,2,3,4',',',help_topic_id+1),',',-1)
eg:
根据第一步,当 help_topic_id = 0时,获取到的字符串 = 1,此时第二步截取的字符串 = 1
根据第一步,当 help_topic_id = 1时,获取到的字符串 = 1,2,此时第二步截取的字符串 = 2
…(以此类推)
扩展
find_in_set
如果匹配到了会得出1,实际业务中我们只需要 where find_in_set(id,ids)>0
就可以判断出,id列,是否再ids列中出现过,做表连接的时候,也可以这样
instr
instr(ids,id)
可以匹配到id在ids最开始出现的位置
select instr('12,31,23,45',23)
所以我们可以 where instr(ids,id) > 0,就可以判断出id在ids中出现过;
但这有一个问题,如果逗号分隔开的字符串,包含我们查找的字符串,也会显示出来,这就不符合我们 根据分隔符 , 判断 查找字符串id 是否出现在 ids 中;如下:
select instr('1234,34,54,44','12')
我们本来想查以逗号为分隔的完全匹配,但是12345包含了 123 所以查出来的结果也是>0的,这不对;
所以我们为了避免这种情况,可以加上分隔符;然后再用 字符串+分隔符作为 查找的字符串 来 匹配;
select instr('1234,34,54,44',concat('12',','))