文章目录
MySQL-行转列
MySQL-行转列场景介绍
表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;
MySQL-使用自连接的方法实现多行转多列
实例:由姓名将打怪数进行汇总
由左表生成右表
- 生成带姓名的杀怪数目表
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
MySQL-使用CASE方法实现行转列
实例:由姓名将打怪数进行汇总
由左表生成右表
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;
MySQL-单列转多行
MySQL-使用序列化表的方法实现单列转多行
单列转成多行
左表转右表
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()
MySQL-多列转多行
MySQL-使用UNION的方法实现多列转多行
多列转多行
左表转右表
取经四人组的装备表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
MySQL-使用序列化表的方法实现多列转多行
多列转多行
左表转右表
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
如何生成唯一序列号
MySQL-在数据库中生成唯一序列号的常用方法
使用系统自增的方式生成序列号会产生序列号的空洞,序列号会在删除3这一行后缺少3,变为序列号1,2,4
如何使用SQL语句建立特殊需求的序列号
前面八位是年月日,后年是随机序列,在一天内随机序列不能重复
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;
MySQL-利用主键删除重复数据
表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;
MySQL-如何处理复杂的重复数据删除
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;