使用到数据库自带的mysql.help_topic表来属性拆分,help_topic表就是实现行转列功能

列转行

  1. SELECT
  2. SUBSTRING_INDEX(
  3. SUBSTRING_INDEX('1,2,3,4,5',',',help_topic_id + 1),',' ,- 1) lzh
  4. FROM
  5. mysql.help_topic
  6. WHERE
  7. help_topic_id < (LENGTH('1,2,3,4,5')) - LENGTH(REPLACE ('1,2,3,4,5', ',', '')) + 1;

  1. SELECT SUBSTRING_INDEX(SUBSTRING_INDEX('7654,7698,7782,7788',',',help_topic_id+1),',',-1) AS num
  2. FROM mysql.help_topic
  3. 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 个分隔符之后的所有字符。

  1. # 获取第2个以逗号为分隔符之前的所有字符。
  2. SELECT SUBSTRING_INDEX('1,2,3,4',',',2);
  3. # 获取最后一个到倒数第2个以逗号分隔符之后的所有字符
  4. SELECT SUBSTRING_INDEX('1,2,3,4',',',-2);
  5. # 所以,我们的核心代码中的 -1 ,就是获取以逗号为分隔符的最后一个值;也就是4

替换函数

replace(str,from_str,to_str)
参数名 解释
str 需要进行替换的字符串
from_str 需要被替换的字符串
to_str 需要替换的字符串

  1. # 将分隔符逗号替换为空。
  2. SELECT REPLACE('1,2,3,4',',','');

获取字符串长度

length(str)
参数名 解释
str 需要计算长度的字符串

  1. # 获取 '1,2,3,4' 字符串的长度
  2. SELECT LENGTH('1,2,3,4')

列转行实现解析

需要解析的SQL

  1. SELECT SUBSTRING_INDEX(SUBSTRING_INDEX('1,2,3,4',',',help_topic_id+1),',',-1) AS num
  2. FROM mysql.help_topic
  3. 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 递增的行即可)

  1. 首先获取最后需被拆分成多少个字符串,利用help_topic_id 来模拟遍历第n个字符串

这一步核心是获取,有多少个分隔符,就有多少个逗号
代码片段:

  1. 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行数据;

  1. 根据“,”逗号来拆分字符串,此处利用 SUBSTRING_INDEX(str, delim, count) 函数,最后把结果赋值给 num 字段

代码片段

  1. 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个分隔符开始获取。

  1. SUBSTRING_INDEX('1,2,3,4',',',help_topic_id+1)
  2. eg
  3. help_topic_id = 0时,获取到的字符串 = 1
  4. help_topic_id = 1时,获取到的字符串 = 1,2 …(以此类推)

第二步:
以”,”逗号为分隔符,截取倒数第1个分隔符之后的所有字符串。

  1. SUBSTRING_INDEX(SUBSTRING_INDEX('1,2,3,4',',',help_topic_id+1),',',-1)
  2. eg
  3. 根据第一步,当 help_topic_id = 0时,获取到的字符串 = 1,此时第二步截取的字符串 = 1
  4. 根据第一步,当 help_topic_id = 1时,获取到的字符串 = 1,2,此时第二步截取的字符串 = 2
  5. …(以此类推)

扩展

find_in_set

如果匹配到了会得出1,实际业务中我们只需要 where find_in_set(id,ids)>0
就可以判断出,id列,是否再ids列中出现过,做表连接的时候,也可以这样

instr

instr(ids,id)
可以匹配到id在ids最开始出现的位置

  1. select instr('12,31,23,45',23)

所以我们可以 where instr(ids,id) > 0,就可以判断出id在ids中出现过;

但这有一个问题,如果逗号分隔开的字符串,包含我们查找的字符串,也会显示出来,这就不符合我们 根据分隔符 , 判断 查找字符串id 是否出现在 ids 中;如下:

  1. select instr('1234,34,54,44','12')

我们本来想查以逗号为分隔的完全匹配,但是12345包含了 123 所以查出来的结果也是>0的,这不对;
所以我们为了避免这种情况,可以加上分隔符;然后再用 字符串+分隔符作为 查找的字符串 来 匹配;

  1. select instr('1234,34,54,44',concat('12',','))