因为不少业务表由于历史缘由或者性能缘由,都使用了违反第一范式的设计模式,即同一个列中存储了多个属性值。这种模式下,应用经常须要将这个列依据分隔符进行分割,并获得列转行的结果:这里使用substring_index函数进行处理mysql
建表语句:sql
1 DROP table if EXISTS tbl_name; 2 CREATE TABLE tbl_name( 3 id int(11) not null auto_increment, 4 userName varchar(100) not null, 5 PRIMARY KEY(id) 6 ) 7 ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8; 8 9 insert into tbl_name values (1,'a,aa,aaa'); 10 insert into tbl_name values (2,'b,bb'); 11 insert into tbl_name values (3,'c,cc');
以下图:设计模式
sql语句:函数
1 SELECT a.id,SUBSTRING_INDEX(SUBSTRING_INDEX(a.userName,',',b.help_topic_id+1),',',-1) as name 2 from tbl_name a left join mysql.help_topic b 3 on b.help_topic_id < (LENGTH(a.userName)-LENGTH(REPLACE(a.userName,',',''))+1) 4 ORDER BY a.id;
执行结果:性能
分析以下:spa
LENGTH(a.userName)-LENGTH(REPLACE(a.userName,',',''))+1
表示了按逗号分割后,得到行转成列的数量,如下简称n;设计
根据id进行循环 { 判断:i 是否 <= n { 获取最靠近第 i 个逗号以前的数据, 即 SUBSTRING_INDEX(SUBSTRING_INDEX(a.userName,',',b.help_topic_id+1),',',-1) i = i +1 } id = id +1 }
总结:3d
这种方法的缺点在于,咱们须要一个拥有连续数列的独立表。而且连续数列的最大值必定要大于符合分割的值的个数。固然,mysql内部也有现成的连续数列表可用。如mysql.help_topic: help_topic_id 共有504个数值,通常能知足于大部分需求了。code