在MySQL中,行列转换是一种常见的操作。它包括行转列和列转行两种情况。
- 行转列:行转列是将表中的某些行转换成列,以提供更为清晰、易读的数据视图。例如,假设我们有一个包含科目和分数的表,我们可以使用SUM和CASE语句将每个科目的分数转换为单独的列。此外,从MySQL 8.0版本开始,还提供了PIVOT函数来实现行转列的操作。例如:
SELECT aggregated_column, [pivot_value_1], [pivot_value_2], ..., [pivot_value_n] FROM (select...) AS source_table PIVOT ( aggregate_function (column_for_aggregation) FOR column_for_pivot IN ([pivot_value_1], [pivot_value_2], ..., [pivot_value_n]) ) AS pivot_table;
- 列转行:列转行则是将表中的某些列转换成行,每行包含一列的值。具体的操作方法包括使用聚合函数、group_concat函数或动态SQL语句块等。例如,可以使用GROUP_CONCAT函数将某一列的值拼接成一个字符串,然后用聚合函数进行分组。
测试题:
DROP TABLE IF EXISTS `stu`;
CREATE TABLE `stu` (`sname` varchar(20) CHARACTER SET utf8 COLLATE utf8_bin NULL DEFAULT NULL,`sub` varchar(20) CHARACTER SET utf8 COLLATE utf8_bin NULL DEFAULT NULL,`score` varchar(20) CHARACTER SET utf8 COLLATE utf8_bin NULL DEFAULT NULL
) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_bin ROW_FORMAT = Dynamic;-- ----------------------------
-- Records of stu
-- ----------------------------
INSERT INTO `stu` VALUES ('zs', 'chinese', '100');
INSERT INTO `stu` VALUES ('zs', 'math', '99');
INSERT INTO `stu` VALUES ('zs', 'english', '98');
INSERT INTO `stu` VALUES ('li', 'chinese', '80');
INSERT INTO `stu` VALUES ('li', 'math', '89');
INSERT INTO `stu` VALUES ('li', 'english', '88');
INSERT INTO `stu` VALUES ('ww', 'chinese', '70');
INSERT INTO `stu` VALUES ('ww', 'math', '79');
INSERT INTO `stu` VALUES ('ww', 'english', '78');SET FOREIGN_KEY_CHECKS = 1;
初始化数据:
现在进行行列转换:
select sname,case sub when "chinese" then score end "语文",case sub when "math" then score end "数学",case sub when "english" then score end "英语"from stu;
现在进行分组统计,然后合并:
select sname,max(case sub when "chinese" then score end) "语文",min(case sub when "math" then score end) "数学",avg(case sub when "english" then score end) "英语"from stuGROUP BY sname;
现在行列转化已经完成!
行转化为列:
小结:case [列名] when [条件] then [数据] end
面试题1:
人员情况表(employee)中字段包括,员工号(ID),姓名(name),年龄(age),文化程度(wh):
包括四种情况(本科以上,大专,高中,初中以下),
现在我要根据年龄字段查询统计出:
表中文化程度为本科以上,大专,高中,初中以下,各有多少人,占总人数多少。
结果如下A:
学历 年龄 人数 百分比
本科以上 20 34 14
大专 20 33 13
高中 20 33 13
初中以下 20 100 40
本科以上 21 50 20
。。。。。。
SQL 查询语句如何写?create table employee(id int primary key auto_increment,name varchar(20),age int(2),wh varchar(20)) ;insert into employee(id,name,age,wh) values (null,'a',20,'本科以上') ;
insert into employee(id,name,age,wh) values (null,'b',20,'本科以上') ;
insert into employee(id,name,age,wh) values (null,'c',21,'本科以上') ;
insert into employee(id,name,age,wh) values (null,'d',20,'本科以上') ;
insert into employee(id,name,age,wh) values (null,'e',20,'大专') ;
insert into employee(id,name,age,wh) values (null,'e',21,'大专') ;
insert into employee(id,name,age,wh) values (null,'e',21,'高中') ;
insert into employee(id,name,age,wh) values (null,'e',20,'高中') ;
insert into employee(id,name,age,wh) values (null,'e',20,'初中以下') ;
起始数据:
通过wh[文化]、age[年龄]分组,即可统计出来:
select wh '学历',age '年龄',count(*) '人数', round((count(*)/(select count(0) from employee)) * 100) '百分比'
from employee
GROUP BY wh ,age
ORDER BY age;
面试题2:
-- 8:00--12:00 为迟到, 12:00--18:00 为早退
-- 打卡表 cardcreate table card(cid int(10),ctime timestamp ,cuser int(10));-- 人员表 person
create table person(pid int(10),name varchar(10)
) ;-- 插入人员表的数据
insert into person values(1,'a');
insert into person values(2,'b');-- 插入打卡的数据
insert into card values(1,'2009-07-19 08:02:00',1);
insert into card values(2,'2009-07-19 18:02:00',1);
insert into card values(3,'2009-07-19 09:02:00',2);
insert into card values(4,'2009-07-19 17:02:00',2);
insert into card values(5,'2009-07-20 08:02:00',1);
insert into card values(6,'2009-07-20 16:02:00',1);
insert into card values(7,'2009-07-20 07:02:00',2);
insert into card values(8,'2009-07-20 20:02:00',2);-- 查询 迟到 早退的员工姓名?
查询结果如下:
工号 姓名 打卡日期 上班打卡 下班打卡 迟到 早退
1 a 2009-07-19 08:02:00 18:02:00 是 否
1 a 2009-07-20 08:02:00 16:02:00 是 是
2 b 2009-07-19 09:02:00 17:02:00 是 是
初始化表:
-- 先查出每一个员工打卡的时间
select p.*,c.ctime
from person p join card c on c.cuser = p.pid;-- 将日期格式化
select p.pid "工号",p.name "姓名",DATE_FORMAT(c.ctime,'%y-%m-%d') "打卡日期",DATE_FORMAT(c.ctime,'%h:%i:%s') "打卡时间"
from person p join card c on c.cuser = p.pid;-- 将日期分离成上下午
select p.pid "工号",p.name "姓名",DATE_FORMAT(c.ctime,'%y-%m-%d') "打卡日期",DATE_FORMAT(c.ctime,'%h:%i:%s') "打卡时间"
from person p join card c on c.cuser = p.pid