老规矩,先弄一波测试数据,数据填充代码没有什么意义,先折叠起来:
/* 第一步:创建临时表结构 */ CREATE TABLE #Student --创建临时表 ( StuName nvarchar(20), --学生名称 Chinese int, Math int, English int ) DROP TABLE #Student --删除临时表 SELECT * FROM #Student --查询所有数据 INSERT INTO #Student(StuName,Chinese,Math,English) VALUES('张三',70,86,96); INSERT INTO #Student(StuName,Chinese,Math,English) VALUES('李四',49,85,86); INSERT INTO #Student(StuName,Chinese,Math,English) VALUES('王五',59,58,90); INSERT INTO #Student(StuName,Chinese,Math,English) VALUES('赵六',68,79,80);
一:列转行,下面是转换之前与之后的截图对比
如果想要行转列,参考上一篇:Sql server 中将数据行转列列转行(一)
方法一:使用 UNION ALL 拼接多个结果集
SELECT * FROM ( SELECT StuName,课程='语文',分数=Chinese FROM #Student UNION ALL SELECT StuName,课程='数学',分数=Math FROM #Student UNION ALL SELECT StuName,课程='英语',分数=English FROM #Student )AS TE ORDER BY TE.StuName ASC
方法二:使用UNPIVOT,推荐此方法;
SELECT * FROM #Student UNPIVOT (分数 FOR 课程 IN([Chinese],Math,English)) T
方法三:使用UNPIVOT,处理动态列情况,看过我上一篇内容的,应该知道,在进行行转列的时候,有时候不太确定到底有多少行的可能,
会有动态的情况,但是在处理列转行的情况时,一般每个数据库在进行数据存储的时候,列有多少个,都是已经确定的,不存在不确定性,
所以,第三种方法知道就可以了,实用性不大,不推荐此方法。
DECLARE @sql NVARCHAR(4000) SELECT @sql=isnull(@sql+',','')+quotename(Name) FROM syscolumns WHERE ID=object_id('Student') AND Name NOT IN('StuName') --不显示学生名称列 ORDER BY Colid --print @sql SET @sql=' SELECT * FROM #Student UNPIVOT (分数 FOR 课程 IN('+@sql+')) T ' Exec(@sql)
注意:上面的这一部分,由于查询了syscolumns 数据库内置系统表,我演示的数据是临时表,是查不到任何数据的,必须创建实际的数据库表才可以使用。