SqlServer行转列(PIVOT),列转行(UNPIVOT)总结
PIVOT用于将列值旋转为列名(即行转列)
语法:
1 2 3 4 5 6 | table_source PIVOT( 聚合函数(value_column) FOR pivot_column IN (<column_list>) ) |
UNPIVOT用于将列明转为列值(即列转行)
语法:
1 2 3 4 5 6 | table_source UNPIVOT( value_column FOR pivot_column IN (<column_list>) ) |
注意:PIVOT、UNPIVOT是SQL Server 2005的语法,使用需修改数据库兼容级别
在数据库属性->选项->兼容级别改为
90
一、行转列
1、建立表格
1 2 3 4 5 6 7 8 9 10 11 | ifobject_id( 'tb' )isnotnulldroptabletb go Create table tb(姓名 varchar (10),课程 varchar (10),分数 int ) Insert into tb values ( '张三' , '语文' ,74) Insert into tb values ( '张三' , '数学' ,83) Insert into tb values ( '张三' , '物理' ,93) Insert into tb values ( '李四' , '语文' ,74) Insert into tb values ( '李四' , '数学' ,84) Insert into tb values ( '李四' , '物理' ,94) go Select * from tb |
2、使用SQL Server 2000静态SQL
1 2 3 4 5 6 | select 姓名, Max ( case 课程 when '语文' then 分数 else 0 end )语文, Max ( case 课程 when '数学' then 分数 else 0 end )数学, Max ( case 课程 when '物理' then 分数 else 0 end )物理 From tb Group by 姓名 |
3、使用SQL Server 2000动态SQL
1 2 3 4 5 6 | declare @sqlvarchar(500) set @sql= 'select姓名' select @sql=@sql+ ',max(case课程when ' '' +课程+ '' ' then分数else 0 end)[' +课程+ ']' from (selectdistinct课程fromtb)a --同from tb group by课程,默认按课程名排序 set @sql=@sql+ ' from tb group by姓名' exec (@sql) |
--使用isnull(),变量先确定动态部分
1 2 3 4 5 | declare @sqlvarchar(8000) select @sql= isnull (@sql+ ',' , '' )+ ' max(case课程when ' '' +课程+ '' ' then分数else 0 end) [' +课程+ ']' from (selectdistinct课程fromtb)asa set @sql= 'select姓名,' +@sql+ ' from tb group by姓名' exec (@sql) |
4、使用SQL Server 2005静态SQL
1 | select *fromtb pivot( max (分数) for 课程 in (语文,数学,物理))a |
5、使用SQL Server 2005动态SQL
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | --使用stuff() declare @sqlvarchar(8000) set @sql= '' --初始化变量@sql select @sql=@sql+ ',' +课程fromtbgroupby课程 --变量多值赋值 set @sql=stuff(@sql,1,1, '' ) --去掉首个',' set @sql= 'select * from tb pivot (max(分数) for课程in (' +@sql+ '))a' exec (@sql) --或使用isnull() declare @sqlvarchar(8000) –-获得课程集合 select @sql= isnull (@sql+ ',' , '' )+课程fromtbgroupby课程 set @sql= 'select * from tb pivot (max(分数) for课程in (' +@sql+ '))a' exec (@sql) |
二、行转列结果加上总分、平均分
1、使用SQL Server 2000静态SQL
1 2 3 4 5 6 7 8 | select 姓名, max ( case 课程 when '语文' then 分数else0end)语文, max ( case 课程 when '数学' then 分数else0end)数学, max ( case 课程 when '物理' then 分数else0end)物理, sum (分数)总分, cast ( avg (分数*1.0)asdecimal(18,2))平均分 fromtb groupby姓名 |
2、使用SQL Server 2000动态SQL
1 2 3 4 5 6 7 | --SQL SERVER 2000动态SQL declare @sqlvarchar(500) set @sql= 'select姓名' select @sql=@sql+ ',max(case课程when ' '' +课程+ '' ' then分数else 0 end)[' +课程+ ']' from (selectdistinct课程fromtb)a set @sql=@sql+ ',sum(分数)总分,cast(avg(分数*1.0) as decimal(18,2)) 平均分from tb group by姓名' exec (@sql) |
3、使用SQL Server 2005静态SQL
1 2 3 4 5 6 7 8 | selectm.*,n.总分,n.平均分 from ( select *fromtb pivot( max (分数) for 课程 in (语文,数学,物理))a)m, ( select 姓名, sum (分数)总分, cast ( avg (分数*1.0)asdecimal(18,2))平均分 fromtb groupby姓名)n wherem.姓名=n.姓名 |
4、使用SQL Server 2005动态SQL
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | declare @sqlvarchar(8000) set @sql= '' --初始化变量@sql select @sql=@sql+ ',' +课程fromtbgroupby课程 --变量多值赋值 --同select @sql = @sql + ','+课程from (select distinct课程from tb)a set @sql=stuff(@sql,1,1, '' ) --去掉首个',' set @sql= 'select m.* , n.总分,n.平均分from (select * from (select * from tb) a pivot (max(分数) for课程in (' +@sql+ ')) b) m , (select姓名,sum(分数)总分, cast(avg(分数*1.0) as decimal(18,2))平均分from tb group by姓名) n where m.姓名= n.姓名' exec (@sql) --或使用isnull() declare @sqlvarchar(8000) select @sql= isnull (@sql+ ',' , '' )+课程fromtbgroupby课程 set @sql= 'select m.* , n.总分,n.平均分from (select * from (select * from tb) a pivot (max(分数) for课程in (' + @sql+ ')) b) m , (select姓名,sum(分数)总分, cast(avg(分数*1.0) as decimal(18,2))平均分from tb group by姓名) n where m.姓名= n.姓名' exec (@sql) |
二、列转行
1、建立表格
1 2 3 4 5 6 7 | ifobject_id( 'tb' )isnotnulldroptabletb go createtabletb(姓名 varchar (10),语文 int ,数学 int ,物理 int ) insertintotbvalues( '张三' ,74,83,93) insertintotbvalues( '李四' ,74,84,94) go select *fromtb |
2、使用SQL Server 2000静态SQL
1 2 3 4 5 6 7 8 9 10 | --SQL SERVER 2000静态SQL。 select * from ( select 姓名,课程= '语文' ,分数=语文fromtb unionall select 姓名,课程= '数学' ,分数=数学fromtb unionall select 姓名,课程= '物理' ,分数=物理fromtb ) t orderby姓名, case 课程 when '语文' then1when '数学' then2when '物理' then3end |
2、使用SQL Server 2000动态SQL
1 2 3 4 5 6 7 8 9 | --SQL SERVER 2000动态SQL。 --调用系统表动态生态。 declare @sqlvarchar(8000) select @sql= isnull (@sql+ ' union all ' , '' )+ ' select姓名, [课程]=' +quotename( Name , '' '' )+ ' , [分数] = ' +quotename( Name )+ ' from tb' fromsyscolumns whereName!= '姓名' andID=object_id( 'tb' ) --表名tb,不包含列名为姓名的其他列 orderbycolid exec (@sql+ ' order by姓名' ) |
3、使用SQL Server 2005静态SQL
1 2 | --SQL SERVER 2005动态SQL select 姓名,课程,分数fromtb unpivot (分数 for 课程 in ([语文],[数学],[物理])) t |
4、使用SQL Server 2005动态SQL
1 2 3 4 5 6 7 8 | --SQL SERVER 2005动态SQL declare @sqlnvarchar(4000) select @sql= isnull (@sql+ ',' , '' )+quotename( Name ) fromsyscolumns whereID=object_id( 'tb' )andNamenotin( '姓名' ) orderbyColid set @sql= 'select姓名,[课程],[分数] from tb unpivot ([分数] for [课程] in(' +@sql+ '))b' exec (@sql) |
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 地球OL攻略 —— 某应届生求职总结
· 提示词工程——AI应用必不可少的技术
· Open-Sora 2.0 重磅开源!
· 字符编码:从基础到乱码解决