今天头一次在mysql中遇到了需要把某一列的数据(是以逗号分隔开的字符串)进行拆分然后分类接着再做分组处理等等,最开始拿到这个完全是懵逼的,这是网上找到的一个亲测有效的方式,可以有效地把需要拆分的列依次罗列下来,这个例子看上去很复杂,其实只需要几个条件:
1.原数据表(就是你需要操作处理的表)
2.建一个放数据的新表(具体方式看例子)
3.本文章最下面的代码,把相应的表名和需要处理的字段修改过来就可以了
4.最后做group by 分类操作,求占比等等 就直接在那个新表操作就行了
表数据:
ID
Value
1
tiny,small,big
2
small,medium
3
tiny,big
期望得到结果:
ID
Value
1
tiny
1
small
1
big
2
small
2
medium
3
tiny
3
big
正文:
#需要处理的表create table tbl_name (ID int ,mSize varchar(100));insert into tbl_name values (1,'tiny,small,big');insert into tbl_name values (2,'small,medium');insert into tbl_name values (3,'tiny,big');
#用于循环的自增表create table incre_table (AutoIncreID int);insert into incre_table values (1);insert into incre_table values (2);insert into incre_table values (3);
select a.ID,substring_index(substring_index(a.mSize,',',b.AutoIncreID),',',-1)fromtbl_name ajoinincre_table bon b.AutoIncreID <= (length(a.mSize) - length(replace(a.mSize,',',''))+1)order by a.ID;
原理分析:
这个join最基本原理是笛卡尔积。通过这个方式来实现循环。
以下是具体问题分析:
length(a.Size) - length(replace(a.mSize,',',''))+1
表示了,按照逗号分割后,改列拥有的数值数量,下面简称n
join过程的伪代码:
根据ID进行循环
{
判断:i 是否 <= n
{
获取最靠近第 i
个逗号之前的数据,即 substring_index(substring_index(a.mSize,',',b.ID),',',-1)
i = i +1
}
ID = ID +1
}
总结:
这种方法的缺点在于,我们需要一个拥有连续数列的独立表(这里是incre_table)。并且连续数列的最大值一定要大于符合分割的值的个数。
例如有一行的mSize 有100个逗号分割的值,那么我们的incre_table 就需要有至少100个连续行。
当然,mysql内部也有现成的连续数列表可用。如mysql.help_topic: help_topic_id
共有504个数值,一般能满足于大部分需求了。
改写后如下:
select a.ID,substring_index(substring_index(a.mSize,',',b.help_topic_id+1),',',-1)fromtbl_name ajoinmysql.help_topic bon b.help_topic_id < (length(a.mSize) - length(replace(a.mSize,',',''))+1)order by a.ID;
改良后:
select
substring_index(substring_index(a.f15,',',b.help_topic_id+1),',',-1) as num ,count(*) as count
from
hw_userinfo_20160509 a
join
mysql.help_topic b
on b.help_topic_id < (length(a.f15) -
length(replace(a.f15,',',''))+1)
GROUP BY num
order by count desc;
反推方式
使用GROUP_CONCAT()函数
select GROUP_CONCAT(name) from aa
GROUP BY id
SELECT uid,GROUP_CONCAT(DISTINCT cast(
contentid as char)),COUNT(DISTINCT contentid) num from yy_user_behavior where uid != 0 AND
contentid != 0 GROUP BY uid order by num desc
GROUP_CONCAT 和GROUP 一起使用,用于数据分组连接。
语法:
GROUP_CONCAT([DISTINCT] expr [,expr ...] [ORDER BY {unsigned_integer | col_name | expr} [ASC |DESC] [,col_name ...]] [SEPARATOR str_val])
如果是参数是number,则返回的GROUP_CONCAT(volumn)值为BLOB类型,需要使用cast,convert转换类型
CAST(expr AS type), CONVERT(expr,type) , CONVERT(expr USING transcoding_name)
CAST() 和CONVERT() 函数可用来获取一个类型的值,并产生另一个类型的值。
select group_concat(CAST(id as char)) from t_dep 返回逗号隔开的串
select group_concat(Convert(id , char)) from t_dep 返回逗号隔开的串
可以转换的type如下:
二进制,同带binary前缀的效果 : BINARY
字符型,可带参数 : CHAR()
日期 : DATE
时间: TIME
日期时间型 : DATETIME
浮点数 : DECIMAL
整数 : SIGNED
无符号整数 : UNSIGNED