表user1:
CREATE TABLE `user1` ( `id` int(11) NOT NULL, `user_name` varchar(3) DEFAULT NULL, `over` varchar(5) DEFAULT NULL, `mobile` varchar(100) DEFAULT NULL, PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
表user2:
CREATE TABLE `user2` ( `id` int(11) NOT NULL, `user_name` varchar(3) DEFAULT NULL, `over` varchar(5) DEFAULT NULL, PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
表user_kills:
CREATE TABLE `user_kills` ( `id` int(11) NOT NULL, `user_id` int(11) DEFAULT NULL, `Timestr` timestamp NULL DEFAULT CURRENT_TIMESTAMP, `kills` decimal(11,0) DEFAULT NULL, PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
实例:由姓名将打怪数进行汇总
由左表生成右表
SELECT a.user_name, b.kills FROM user1 a JOIN user_kills b ON a.id = b.user_id
SELECT a.user_name, sum(b.kills) FROM user1 a JOIN user_kills b ON a.id = b.user_id GROUP BY a.user_name
3. 行显转化成列显
3.1 只显示孙悟空的打怪数
SELECT a.user_name, sum(b.kills) FROM user1 a JOIN user_kills b ON a.id = b.user_id and a.user_name = '孙悟空'
3.2 只显示猪八戒的打怪数
SELECT a.user_name, sum(b.kills) FROM user1 a JOIN user_kills b ON a.id = b.user_id and a.user_name = '猪八戒'
3.3 只显示沙僧的打怪数
SELECT a.user_name, sum(b.kills) FROM user1 a JOIN user_kills b ON a.id = b.user_id and a.user_name = '沙僧'
3.4 把多个sql合并成一个sql
SELECT * FROM ( SELECT sum(b.kills) AS '孙悟空' FROM user1 a JOIN user_kills b ON a.id = b.user_id AND a.user_name = '孙悟空' ) a CROSS JOIN ( SELECT sum(b.kills) AS '猪八戒' FROM user1 a JOIN user_kills b ON a.id = b.user_id AND a.user_name = '猪八戒' ) b CROSS JOIN ( SELECT sum(b.kills) AS '沙僧' FROM user1 a JOIN user_kills b ON a.id = b.user_id AND a.user_name = '沙僧' ) c
实例:由姓名将打怪数进行汇总
由左表生成右表
SELECT SUM( CASE WHEN user_name = '孙悟空' THEN kills END ) AS '孙悟空', SUM( CASE WHEN user_name = '猪八戒' THEN kills END ) AS '猪八戒', SUM( CASE WHEN user_name = '沙僧' THEN kills END ) AS '沙僧' FROM user1 a JOIN user_kills b ON a.id = b.user_id;
单列转成多行
左表转右表
CREATE TABLE `tb_sequence` ( `id` int(11) NOT NULL AUTO_INCREMENT, PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin;
SELECT user_name, REPLACE ( substring( substring_index(mobile, ',', a.id), char_length( substring_index(mobile, ',', a.id - 1) ) + 1 ), ',', '' ) AS mobile FROM tb_sequence a CROSS JOIN ( SELECT user_name, concat(mobile, ',') AS mobile, length(mobile) - length(REPLACE(mobile, ',', '')) + 1 size FROM user1 b ) b ON a.id <= b.size
1.1 子查询:在mobile结尾处增加一个逗号,size计算mobile中有多少个逗号
SELECT user_name, concat(mobile, ',') AS mobile, length(mobile) - length(REPLACE(mobile, ',', '')) + 1 size FROM user1 b
1.2 利用序列表和cross join,每一行都生成size数目的行
SELECT * FROM tb_sequence a CROSS JOIN ( SELECT user_name, concat(mobile, ',') AS mobile, length(mobile) - length(REPLACE(mobile, ',', '')) + 1 size FROM user1 b ) b ON a.id <= b.size
1.3 字符串截取得到结果
SELECT user_name, REPLACE ( substring( substring_index(mobile, ',', a.id), char_length( substring_index(mobile, ',', a.id - 1) ) + 1 ), ',', '' ) AS mobile FROM tb_sequence a CROSS JOIN ( SELECT user_name, concat(mobile, ',') AS mobile, length(mobile) - length(REPLACE(mobile, ',', '')) + 1 size FROM user1 b ) b ON a.id <= b.size
替换user1的表就可以完成列转多行的工作了
mysql 函数substring_index()
多列转多行
左表转右表
取经四人组的装备表user1_equipment:
CREATE TABLE `user1_equipment` ( `id` int(11) NOT NULL AUTO_INCREMENT, `user_id` int(11) NOT NULL, `arms` varchar(10) DEFAULT NULL, `clothing` varchar(10) DEFAULT NULL, `shoe` varchar(10) DEFAULT NULL, PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
1.1 装备表user1_equipment与user1表关联得到左表
SELECT user_name,arms,clothing,shoe from user1 a join user1_equipment b on a.id=b.user_id
1.2 只显示装备列
SELECT user_name, arms FROM user1 a JOIN user1_equipment b ON a.id = b.user_id
1.3 增加一个分类项
SELECT user_name, 'arms' AS equipment, arms AS eq_name FROM user1 a JOIN user1_equipment b ON a.id = b.user_id
1.4 用union进行合并
SELECT user_name, 'arms' AS equipment, arms AS eq_name FROM user1 a JOIN user1_equipment b ON a.id = b.user_id UNION ALL SELECT user_name, 'clothing' AS equipment, clothing AS eq_name FROM user1 a JOIN user1_equipment b ON a.id = b.user_id UNION ALL SELECT user_name, 'eq_name' AS equipment, shoe AS eq_name FROM user1 a JOIN user1_equipment b ON a.id = b.user_id ORDER BY user_name
多列转多行
左表转右表
1.1 装备表user1_equipment与user1表关联得到左表
SELECT user_name,arms,clothing,shoe from user1 a join user1_equipment b on a.id=b.user_id
1.2 利用序列表tb_sequence和cross join将一行转成三行
SELECT user_name, arms, clothing, shoe FROM user1 a JOIN user1_equipment b ON a.id = b.user_id CROSS JOIN tb_sequence c WHERE c.id <= 3 ORDER BY user_name
1.3 利用case when then end当序列表id=1时取arms值,当序列表id=2时取clothing值,当序列表id=3时取shoe值
SELECT user_name, CASE WHEN c.id = 1 THEN arms END, CASE WHEN c.id = 2 THEN clothing END, CASE WHEN c.id = 3 THEN shoe END FROM user1 a JOIN user1_equipment b ON a.id = b.user_id CROSS JOIN tb_sequence c WHERE c.id <= 3 ORDER BY user_name
1.4 利用coalesce取不为空的项
SELECT user_name, COALESCE ( CASE WHEN c.id = 1 THEN arms END, CASE WHEN c.id = 2 THEN clothing END, CASE WHEN c.id = 3 THEN shoe END ) eq_name FROM user1 a JOIN user1_equipment b ON a.id = b.user_id CROSS JOIN tb_sequence c WHERE c.id <= 3 ORDER BY user_name
1.5 利用case when then end显示装备类型列
SELECT user_name, COALESCE ( CASE WHEN c.id = 1 THEN 'arms' END, CASE WHEN c.id = 2 THEN 'clothing' END, CASE WHEN c.id = 3 THEN 'shoe' END ) equipment, COALESCE ( CASE WHEN c.id = 1 THEN arms END, CASE WHEN c.id = 2 THEN clothing END, CASE WHEN c.id = 3 THEN shoe END ) eq_name FROM user1 a JOIN user1_equipment b ON a.id = b.user_id CROSS JOIN tb_sequence c WHERE c.id <= 3 ORDER BY user_name
使用系统自增的方式生成序列号会产生序列号的空洞,序列号会在删除3这一行后缺少3,变为序列号1,2,4
前面八位是年月日,后年是随机序列,在一天内随机序列不能重复
order_seq表:
CREATE TABLE `order_seq` ( `timestr` varchar(11) DEFAULT '', `order_sn` varchar(11) DEFAULT NULL ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
DECLARE v_cnt INT; DECLARE v_timestr INT; DECLARE rowcount BIGINT; SET v_timestr=DATE_FORMAT(NOW(),'%Y%m%d'); SELECT ROUND(RAND()*100,0)+1 INTO v_cnt; START TRANSACTION; UPDATE order_seq SET order_sn = order_sn + v_cnt WHERE timestr=v_timestr; if ROW_COUNT()=0 THEN INSERT INTO order_seq(timestr,order_sn) VALUES(v_timestr,v_cnt); end if; SELECT CONCAT(v_timestr,LPAD(order_sn,7,0)) as order_sn FROM order_seq WHERE timestr=v_timestr; COMMIT;
表user1_test:
CREATE table user1_test ( id INT auto_increment NOT NULL, user_name VARCHAR (3), over VARCHAR (5), mobile VARCHAR (100), PRIMARY KEY (id) ); INSERT INTO user1_test (user_name, over, mobile) SELECT user_name, over, mobile FROM user1; INSERT INTO user1_test (user_name, over, mobile) SELECT user_name, over, mobile FROM user1 LIMIT 2;
删除表user1_test中重复的行
1.1 列出重复的数据
SELECT user_name, over, count(*) FROM user1_test GROUP BY user_name,over HAVING count(*) > 1
DELETE a FROM user1_test a JOIN ( SELECT user_name, count(*), max(id) AS id FROM user1_test GROUP BY user_name HAVING count(*) > 1 ) b ON a.user_name = b.user_name WHERE a.id < b.id select * from user1_test;
1.1 准备好要用的表
create table user1_practice(id int not null auto_increment primary key, user_name varchar(3), over varchar(5), mobile varchar(100)); insert into user1_practice(user_name,over,mobile) values ('唐僧','旃檀功德佛','12112345678,14112345678,12112345678'); insert into user1_practice(user_name,over,mobile) values ('猪八戒','净坛使者','12144643321,14144643321'); insert into user1_practice(user_name,over,mobile) values ('孙悟空','斗战胜佛','12166666666,14166666666,18166666666,18166666666'); insert into user1_practice(user_name,over,mobile) values ('沙僧','金身罗汉','12198343214,14198343214');
1.2 建一个序列表
create tb_sequence(id int not null auto_increment primary key); insert into tb_sequence values(),(),(),(),(),(),(),(),();
1.3 列转行后的表user1_trans1
create table user1_trans1 as select a.id,user_name,over, replace(substring(substring_index(mobile,',',a.id),char_length(substring_index(mobile,',',a.id-1))+1),',','') as mobile from tb_sequence a cross join( select user_name,over, concat(mobile,',') as mobile, length(mobile)-length(replace(mobile,',',''))+1 as size from user1_practice b) b on a.id <= b.size;
1.4 删除user1_trans1表中的重复记录
delete a from user1_trans1 a join ( select user_name,over,mobile,count(*),max(id) as id from user1_trans1 group by user_name,over,mobile having count(*) > 1 ) b on a.user_name = b.user_name and a.over = b.over and a.mobile = b.mobile where a.id < b.id;
1.5 用group_concat函数将mobile转化成以逗号分隔的字符串
create table user1_trans2 as select user_name,over,group_concat(mobile) as mobile from user1_trans1 group by user_name,over;
1.6 对原表user1_practice进行关联更新
update user1_practice a inner join user1_trans2 b on a.user_name = b.user_name set a.mobile = b.mobile;