`
mingnianshimanian
  • 浏览: 40311 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

SQL行列转换

sql 
阅读更多

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
 
方法二:动态获取列名,就是方法一的动态化,这里使用了quotename方法,就是转义标识符

 

 

DECLARE @sql VARCHAR(8000)

SELECT @sql = isnull(@sql + ' union all ','') + ' select name, [course]='

+ quotename(Name,'''') + ' , [score] = ' + quotename(Name) + ' from tbl_grade'

FROM syscolumns

WHERE Name != 'name' AND Name != 'id' AND ID = object_id('tbl_grade')

exec(@sql + ' order by name')

go
 

 

方法三:使用unpivot

 

SELECT name,course,score FROM tbl_grade 

unpivot (score FOR course IN(语文,数学,英语)) t

 

方法四:使用unpivot的动态化

 

DECLARE @sql NVARCHAR(4000)

SELECT @sql = isnull(@sql + ',','') + quotename(Name)

FROM syscolumns

WHERE ID = object_id('tbl_grade') AND Name NOT IN ('name','id')

SET @sql = 'select name,[course],[score] from tbl_grade unpivot ([score] for [course] in(' + @sql + ')) b'

exec(@sql)

 

以上四种方法结果都一样,如下图

 

 

  • 大小: 6.7 KB
  • 大小: 4.4 KB
  • 大小: 5.6 KB
  • 大小: 9.5 KB
分享到:
评论

相关推荐

    sql行列转换扩展

    SQL 行列转换扩展 SQL 行列转换扩展是指将数据库表中的行数据转换为列数据,或者将列数据转换为行数据的操作。这种操作在数据分析和报表生成中非常常见。在本文中,我们将介绍两种类型的行列转换扩展方法:行转列...

    sql试题及答案,sql 行列转换,sql存储过程实例

    通过学习这些SQL试题、行列转换技巧和存储过程实例,你可以全面提升SQL技能,无论是日常的数据查询还是复杂的业务逻辑处理,都能得心应手。在实际工作中,不断练习和探索,将理论知识转化为实践能力,是成为SQL高手...

    SQL行列转换 Pivot UnPivot

    SQL 行列转换 Pivot UnPivot SQL 行列转换是指将表格中的行数据转换为列数据,或者将列数据转换为行数据。Pivot 和 UnPivot 是 SQL Server 2005 中引入的两个语法,用于实现行列转换。 Pivot Pivot 语法的主要...

    sql行列转换、一个字段包含另一个字段.sql

    sql行列转换、一个字段包含另一个字段.sql

    SQL语句行列转换(附带数据库、表、视图操作)

    SQL 语句行列转换(附带数据库、表、视图操作) SQL 语句行列转换是数据库管理系统中的一种常见操作,它可以将数据从行转换为列,或者从列转换为行。在这个过程中,需要使用数据库管理语言(Database Management ...

    oracle sql 行列转换

    在Oracle SQL中,行列转换是一种常见的数据操作需求,主要用于将数据表中的行转换为列,或将列转换为行,以此来满足不同的数据展示或分析需求。这种转换在处理多维度数据、汇总数据或是进行复杂查询时特别有用。下面...

    一个简单的SQL 行列转换语句

    一个简单的SQL 行列转换 Author: eaglet 在数据库开发中经常会遇到行列转换的问题,比如下面的问题,部门,员工和员工类型三张表,我们要统计类似这样的列表 部门编号 部门名称 合计 正式员工 临时员工 辞退员工 1 A...

    ms sql 行列转换

    在SQL中,行列转换是一种常见的数据操作,尤其在数据分析和报表生成时十分有用。这个案例主要涉及了如何将数据从行格式转换为列格式,针对的是一个学生成绩表,其中包含姓名、科目和成绩三个字段。我们将分别介绍...

    sql server 行列转换

    ### SQL Server 行列转换知识点解析 #### 一、行列转换概述 在处理数据库查询时,我们经常会遇到需要将表中的行数据转换为列数据的需求,这种操作通常被称为“行列转换”。例如,当我们需要汇总不同类别的数据并将...

    通过SQL语句实现行列转换的几种方法

    ### 通过SQL语句实现行列转换的几种方法 在日常工作中,我们经常需要处理的数据结构并不总是按照我们期望的方式组织的。特别是在制作自定义报表或进行产品开发时,经常会遇到需要将数据从一种布局转换到另一种布局...

    sql行列转换[借鉴].pdf

    在SQL中,行列转换是一种常见的数据操作,用于将表格数据从行格式转换为列格式,或者反之。在给定的PDF文件中,涉及到的具体知识点主要包括以下几个方面: 1. **CASE语句**:在SQL查询中,`CASE`语句常用于进行条件...

    SQL 2008行列转换的pivot

    ### SQL 2008 行列转换 (Pivot) 的动态实现 #### 知识点一:行列转换(Pivot)的概念与应用场景 在数据库查询中,有时我们需要将数据表中的行转换为列,或者将列转换为行,这种操作被称为行列转换。行列转换在报表...

    mysql行列转换

    java语言 数据库 mysql数据库 sql行列转换的例子 详解

    sql动态转换行列和字符的分割

    在SQL中,行列转换是一种常见的数据操作,尤其在数据分析和报表生成时尤为关键。动态添加列则是在查询过程中根据特定条件或数据集自动生成列,这在处理不断变化的数据结构时非常有用。以下是对这些主题的详细解释: ...

    Sql语句实现表的行列转换,行转列,列转行

    ### SQL语句实现表的行列转换,行转列,列转行 在处理数据库时,我们经常需要对数据进行各种变换以适应不同的分析需求。其中,“行列转换”就是一种非常实用的功能,它可以帮助我们将表中的行数据转换为列数据,...

Global site tag (gtag.js) - Google Analytics