SQL行列转换使用较为频繁,面试当中也经常有这样的题目,汇总了mysql 和sql server几种常见的方法,如有错误请指正。
MYSQL行转列
CREATE TABLE `tbl_grade` ( `id` bigint(10) NOT NULL AUTO_INCREMENT, `name` varchar(10) DEFAULT NULL, `course` varchar(10) DEFAULT NULL, `score` decimal(5,0) DEFAULT NULL, PRIMARY KEY (`id`) ) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;
INSERT INTO tbl_grade (`name`, `course`, `score`) VALUES ('张三', '语文', '74'); INSERT INTO tbl_grade (`name`, `course`, `score`) VALUES ('张三', '数学', '55'); INSERT INTO tbl_grade (`name`, `course`, `score`) VALUES ('张三', '英语', '66'); INSERT INTO tbl_grade (`name`, `course`, `score`) VALUES ('李四', '语文', '88'); INSERT INTO tbl_grade (`name`, `course`, `score`) VALUES ('李四', '数学', '76'); INSERT INTO tbl_grade (`name`, `course`, `score`) VALUES ('李四', '英语', '69'); INSERT INTO tbl_grade (`name`, `course`, `score`) VALUES ('王五', '语文', '11'); INSERT INTO tbl_grade (`name`, `course`, `score`) VALUES ('王五', '数学', '45'); INSERT INTO tbl_grade (`name`, `course`, `score`) VALUES ('王五', '英语', '68');
方法一:使用表链接
SELECT DISTINCT a.name, (SELECT score FROM tbl_grade b WHERE a.name = b.name AND b.course = '语文') AS '语文', (SELECT score FROM tbl_grade b WHERE a.name = b.name AND b.course = '数学') AS '数学', (SELECT score FROM tbl_grade b WHERE a.name = b.name AND b.course = '英语') AS '英语', SUM(score) AS '总分', cast(avg(score*1.0) as decimal(18,2)) as '平均分' FROM tbl_grade a GROUP BY a.name
方法二:使用分组,对每个分组分别处理
SELECT DISTINCT a.name, SUM(CASE course WHEN '语文' THEN score END) AS '语文', SUM(CASE course WHEN '数学' THEN score END) AS '数学', SUM(CASE course WHEN '英语' THEN score END) AS '英语', SUM(score) AS '总分', cast(avg(score*1.0) as decimal(18,2)) as '平均分' FROM tbl_grade a GROUP BY a.name
也可以把case when then 换成if
SELECT DISTINCT a.name, SUM(IF (course = '语文' , score , null ) ) as '语文', SUM(IF (course = '数学' , score , null ) ) as '数学', SUM(IF (course = '英语' , score , null ) ) as '英语', SUM(score) AS '总分', cast(avg(score*1.0) as decimal(18,2)) as '平均分' FROM tbl_grade a GROUP BY a.name
方法四:使用了存储过程,其实是第二种方法的动态化,先计算出所有课程的数量,然后对每个分组进行课程查询。
很明显前两种方法属于硬编码,增加课程后就需要修改SQL。而第三种则不需要修改SQL。
#MySQL中不能在一个存储过程中删除另一个存储过程 #DROP PROCEDURE IF EXISTS sp_count(); DELIMITER && CREATE PROCEDURE sp_count() BEGIN #课程名称 DECLARE course_name VARCHAR(20); #所有课程数量 DECLARE count INT; #计数器 DECLARE i INT DEFAULT 0; #拼接SQL字符串 SET count = (SELECT COUNT(distinct course) FROM tbl_grade); SET @s = 'SELECT name'; WHILE i < count DO SET course_name = (SELECT course FROM tbl_grade LIMIT i,1); SET @s = CONCAT(@s,',SUM(CASE course WHEN ','\'',course_name,'\'',' THEN score END )',' AS ','\'',course_name,'\''); SET i = i+1; END WHILE; SET @s = CONCAT(@s,',sum(score) as 总分,cast(avg(score*1.0) as decimal(18,2)) as 平均分 FROM tbl_grade GROUP BY name'); PREPARE stmt FROM @s; EXECUTE stmt; END && call sp_count();
以上方法处理结果都一样如下图
MYSQL列转行
CREATE TABLE tbl_course( `id` BIGINT(10) not NULL AUTO_INCREMENT, `name` VARCHAR(10) DEFAULT NULL, `语文` DECIMAL(5,0) DEFAULT null, `数学` DECIMAL(5,0) DEFAULT null, `英语` DECIMAL(5,0) DEFAULT null, PRIMARY KEY (`id`) ) ENGINE = INNODB AUTO_INCREMENT = 1 DEFAULT CHARSET=utf8
INSERT INTO tbl_course (`name`,`语文`,`数学`,`英语`) VALUES ('张三','77','44','22'); INSERT INTO tbl_course (`name`,`语文`,`数学`,`英语`) VALUES ('李四','55','12','85'); INSERT INTO tbl_course (`name`,`语文`,`数学`,`英语`) VALUES ('王五','85','45','96');
方法一:手动列举列,然后union数据
SELECT tepTable.* FROM ( SELECT name, "语文", 语文 as score FROM tbl_course union all SELECT name, "数学", 数学 as score FROM tbl_course union all SELECT name, "英语", 英语 as score FROM tbl_course ) tepTable ORDER BY tepTable.`name`
方法二:使用存储过程,从MySQL schem获取表最新表字段,拼接SQL。实际上是方法一的动态扩展。
DELIMITER $$ CREATE PROCEDURE sp_trans() BEGIN #课程名称 DECLARE course_n VARCHAR(20); #所有课程数量 DECLARE count INT; #计数器 DECLARE i INT DEFAULT 0; #拼接SQL字符串 SET @s = 'SELECT * FROM ('; SET count = (SELECT COUNT(*) FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_SCHEMA ='test' AND TABLE_NAME='tbl_course' AND COLUMN_NAME <> 'name' AND COLUMN_NAME <> 'id'); WHILE i < count DO SET course_n = (SELECT COLUMN_NAME FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_SCHEMA ='test' AND TABLE_NAME='tbl_course' AND COLUMN_NAME <> 'name' AND COLUMN_NAME <> 'id' LIMIT i,1); SET @s = CONCAT(@s, ' SELECT name, "'); SET @s = CONCAT(@s, course_n); SET @s = CONCAT(@s, '", '); SET @s = CONCAT(@s, course_n); SET @s = CONCAT(@s,' as score FROM tbl_course '); IF i <> count-1 THEN SET @s = CONCAT(@s, 'union all'); END IF; SET i = i+1; END WHILE; SET @s = CONCAT(@s, ' ) tepTable ORDER BY tepTable.`name`'); PREPARE stmt FROM @s; EXECUTE stmt; END $$ CALL sp_trans
2种方法查询结果都一样,如下图
MSSQL行转列
if exists (select * from sysobjects where id = object_id('tbl_grade') and type = 'U') drop table tbl_grade go CREATE TABLE tbl_grade ( id bigint NOT NULL identity, name varchar(10) DEFAULT NULL, course varchar(10) DEFAULT NULL, score decimal(5,0) DEFAULT NULL, PRIMARY KEY (id) ) insert into tbl_grade VALUES ('张三','语文',74) insert into tbl_grade VALUES ('张三','数学',83) insert into tbl_grade VALUES ('张三','英语',93) insert into tbl_grade VALUES ('李四','语文',74) insert into tbl_grade VALUES ('李四','数学',84) insert into tbl_grade VALUES ('李四','英语',94) insert into tbl_grade VALUES ('王五','语文',54) insert into tbl_grade VALUES ('王五','数学',63) insert into tbl_grade VALUES ('王五','英语',72) SELECT * FROM tbl_grade
SELECT name,SUM(语文) AS 语文,SUM(数学) AS 数学,SUM(英语) AS 英语 FROM tbl_grade g pivot( MAX(score) FOR course IN (语文,数学,英语)) a GROUP BY name
MSSQL列转行
if exists (select * from sysobjects where id = object_id('tbl_grade') and type = 'U') drop table tbl_grade go CREATE TABLE tbl_grade ( id bigint NOT NULL identity, name varchar(10) DEFAULT NULL, 语文 decimal(5,0) DEFAULT NULL, 数学 decimal(5,0) DEFAULT NULL, 英语 decimal(5,0) DEFAULT NULL, PRIMARY KEY (id) ) INSERT INTO tbl_grade (name,语文,数学,英语) VALUES ('张三',99,44,22) INSERT INTO tbl_grade (name,语文,数学,英语) VALUES ('李四',55,12,85) INSERT INTO tbl_grade (name,语文,数学,英语) VALUES ('王五',85,45,96)
方法一:静态union all
SELECT * FROM ( SELECT name,course='语文',score = 语文 FROM tbl_grade UNION ALL SELECT name,course='数学',score = 数学 FROM tbl_grade UNION ALL SELECT name,course='英语',score = 英语 FROM tbl_grade ) t ORDER BY name,CASE course WHEN '语文' THEN 1 WHEN '数学' THEN 2 WHEN '英语' THEN 3 end
相关推荐
SQL 行列转换扩展 SQL 行列转换扩展是指将数据库表中的行数据转换为列数据,或者将列数据转换为行数据的操作。这种操作在数据分析和报表生成中非常常见。在本文中,我们将介绍两种类型的行列转换扩展方法:行转列...
通过学习这些SQL试题、行列转换技巧和存储过程实例,你可以全面提升SQL技能,无论是日常的数据查询还是复杂的业务逻辑处理,都能得心应手。在实际工作中,不断练习和探索,将理论知识转化为实践能力,是成为SQL高手...
SQL 行列转换 Pivot UnPivot SQL 行列转换是指将表格中的行数据转换为列数据,或者将列数据转换为行数据。Pivot 和 UnPivot 是 SQL Server 2005 中引入的两个语法,用于实现行列转换。 Pivot Pivot 语法的主要...
sql行列转换、一个字段包含另一个字段.sql
SQL 语句行列转换(附带数据库、表、视图操作) SQL 语句行列转换是数据库管理系统中的一种常见操作,它可以将数据从行转换为列,或者从列转换为行。在这个过程中,需要使用数据库管理语言(Database Management ...
在Oracle SQL中,行列转换是一种常见的数据操作需求,主要用于将数据表中的行转换为列,或将列转换为行,以此来满足不同的数据展示或分析需求。这种转换在处理多维度数据、汇总数据或是进行复杂查询时特别有用。下面...
一个简单的SQL 行列转换 Author: eaglet 在数据库开发中经常会遇到行列转换的问题,比如下面的问题,部门,员工和员工类型三张表,我们要统计类似这样的列表 部门编号 部门名称 合计 正式员工 临时员工 辞退员工 1 A...
在SQL中,行列转换是一种常见的数据操作,尤其在数据分析和报表生成时十分有用。这个案例主要涉及了如何将数据从行格式转换为列格式,针对的是一个学生成绩表,其中包含姓名、科目和成绩三个字段。我们将分别介绍...
### SQL Server 行列转换知识点解析 #### 一、行列转换概述 在处理数据库查询时,我们经常会遇到需要将表中的行数据转换为列数据的需求,这种操作通常被称为“行列转换”。例如,当我们需要汇总不同类别的数据并将...
### 通过SQL语句实现行列转换的几种方法 在日常工作中,我们经常需要处理的数据结构并不总是按照我们期望的方式组织的。特别是在制作自定义报表或进行产品开发时,经常会遇到需要将数据从一种布局转换到另一种布局...
在SQL中,行列转换是一种常见的数据操作,用于将表格数据从行格式转换为列格式,或者反之。在给定的PDF文件中,涉及到的具体知识点主要包括以下几个方面: 1. **CASE语句**:在SQL查询中,`CASE`语句常用于进行条件...
### SQL 2008 行列转换 (Pivot) 的动态实现 #### 知识点一:行列转换(Pivot)的概念与应用场景 在数据库查询中,有时我们需要将数据表中的行转换为列,或者将列转换为行,这种操作被称为行列转换。行列转换在报表...
java语言 数据库 mysql数据库 sql行列转换的例子 详解
在SQL中,行列转换是一种常见的数据操作,尤其在数据分析和报表生成时尤为关键。动态添加列则是在查询过程中根据特定条件或数据集自动生成列,这在处理不断变化的数据结构时非常有用。以下是对这些主题的详细解释: ...
### SQL语句实现表的行列转换,行转列,列转行 在处理数据库时,我们经常需要对数据进行各种变换以适应不同的分析需求。其中,“行列转换”就是一种非常实用的功能,它可以帮助我们将表中的行数据转换为列数据,...