求一个行列转换SQL
原表
项目类型表
编码 名称
001 ERP项目
002 OA项目
003 HR项目
项目清单表
年 月 项目类型 业务员 金额
2012 8 ERP项目 张三 100000
2012 8 OA项目 张三 50000
2012 8 ERP项目 李四 120000
要求得出下面结果集
年 月 业务员 ERP项目金额 OA项目金额 HR项目金额
2012 8 张三 100000 50000 0
2012 8 李四 120000 0 0
数据库版本 SQL2005,项目类型表的数据不能写死在脚本中,要即时查询出来
谢谢
[解决办法]
/*标题:普通行列转换(version 2.0)作者:爱新觉罗.毓华(十八年风雨,守得冰山雪莲花开)时间:2008-03-09地点:广东深圳说明:普通行列转换(version 1.0)仅针对sql server 2000提供静态和动态写法,version 2.0增加sql server 2005的有关写法。问题:假设有张学生成绩表(tb)如下:姓名 课程 分数张三 语文 74张三 数学 83张三 物理 93李四 语文 74李四 数学 84李四 物理 94想变成(得到如下结果): 姓名 语文 数学 物理 ---- ---- ---- ----李四 74 84 94张三 74 83 93-------------------*/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--SQL SERVER 2000 静态SQL,指课程只有语文、数学、物理这三门课程。(以下同)select 姓名 as 姓名 , max(case 课程 when '语文' then 分数 else 0 end) 语文, max(case 课程 when '数学' then 分数 else 0 end) 数学, max(case 课程 when '物理' then 分数 else 0 end) 物理from tbgroup by 姓名--SQL SERVER 2000 动态SQL,指课程不止语文、数学、物理这三门课程。(以下同)declare @sql varchar(8000)set @sql = 'select 姓名 'select @sql = @sql + ' , max(case 课程 when ''' + 课程 + ''' then 分数 else 0 end) [' + 课程 + ']'from (select distinct 课程 from tb) as aset @sql = @sql + ' from tb group by 姓名'exec(@sql) --SQL SERVER 2005 静态SQL。select * from (select * from tb) a pivot (max(分数) for 课程 in (语文,数学,物理)) b--SQL SERVER 2005 动态SQL。declare @sql varchar(8000)select @sql = isnull(@sql + '],[' , '') + 课程 from tb group by 课程set @sql = '[' + @sql + ']'exec ('select * from (select * from tb) a pivot (max(分数) for 课程 in (' + @sql + ')) b')---------------------------------/*问题:在上述结果的基础上加平均分,总分,得到如下结果:姓名 语文 数学 物理 平均分 总分 ---- ---- ---- ---- ------ ----李四 74 84 94 84.00 252张三 74 83 93 83.33 250*/--SQL SERVER 2000 静态SQL。select 姓名 姓名, max(case 课程 when '语文' then 分数 else 0 end) 语文, max(case 课程 when '数学' then 分数 else 0 end) 数学, max(case 课程 when '物理' then 分数 else 0 end) 物理, cast(avg(分数*1.0) as decimal(18,2)) 平均分, sum(分数) 总分from tbgroup by 姓名--SQL SERVER 2000 动态SQL。declare @sql varchar(8000)set @sql = 'select 姓名 'select @sql = @sql + ' , max(case 课程 when ''' + 课程 + ''' then 分数 else 0 end) [' + 课程 + ']'from (select distinct 课程 from tb) as aset @sql = @sql + ' , cast(avg(分数*1.0) as decimal(18,2)) 平均分 , sum(分数) 总分 from tb group by 姓名'exec(@sql) --SQL SERVER 2005 静态SQL。select m.* , n.平均分 , n.总分 from(select * from (select * from tb) a pivot (max(分数) for 课程 in (语文,数学,物理)) b) m,(select 姓名 , cast(avg(分数*1.0) as decimal(18,2)) 平均分 , sum(分数) 总分 from tb group by 姓名) nwhere m.姓名 = n.姓名--SQL SERVER 2005 动态SQL。declare @sql varchar(8000)select @sql = isnull(@sql + ',' , '') + 课程 from tb group by 课程exec ('select m.* , n.平均分 , n.总分 from(select * from (select * from tb) a pivot (max(分数) for 课程 in (' + @sql + ')) b) m , (select 姓名 , cast(avg(分数*1.0) as decimal(18,2)) 平均分 , sum(分数) 总分 from tb group by 姓名) nwhere m.姓名 = n.姓名')drop table tb ------------------------------------/*问题:如果上述两表互相换一下:即表结构和数据为:姓名 语文 数学 物理张三 74 83 93李四 74 84 94想变成(得到如下结果): 姓名 课程 分数 ---- ---- ----李四 语文 74李四 数学 84李四 物理 94张三 语文 74张三 数学 83张三 物理 93--------------*/create table tb(姓名 varchar(10) , 语文 int , 数学 int , 物理 int)insert into tb values('张三',74,83,93)insert into tb values('李四',74,84,94)go--SQL SERVER 2000 静态SQL。select * from( select 姓名 , 课程 = '语文' , 分数 = 语文 from tb union all select 姓名 , 课程 = '数学' , 分数 = 数学 from tb union all select 姓名 , 课程 = '物理' , 分数 = 物理 from tb) torder by 姓名 , case 课程 when '语文' then 1 when '数学' then 2 when '物理' then 3 end--SQL SERVER 2000 动态SQL。--调用系统表动态生态。declare @sql varchar(8000)select @sql = isnull(@sql + ' union all ' , '' ) + ' select 姓名 , [课程] = ' + quotename(Name , '''') + ' , [分数] = ' + quotename(Name) + ' from tb'from syscolumns where name! = N'姓名' and ID = object_id('tb') --表名tb,不包含列名为姓名的其它列order by colid ascexec(@sql + ' order by 姓名 ')--SQL SERVER 2005 动态SQL。select 姓名 , 课程 , 分数 from tb unpivot (分数 for 课程 in([语文] , [数学] , [物理])) t--SQL SERVER 2005 动态SQL,同SQL SERVER 2000 动态SQL。--------------------/*问题:在上述的结果上加个平均分,总分,得到如下结果:姓名 课程 分数---- ------ ------李四 语文 74.00李四 数学 84.00李四 物理 94.00李四 平均分 84.00李四 总分 252.00张三 语文 74.00张三 数学 83.00张三 物理 93.00张三 平均分 83.33张三 总分 250.00------------------*/select * from( select 姓名 as 姓名 , 课程 = '语文' , 分数 = 语文 from tb union all select 姓名 as 姓名 , 课程 = '数学' , 分数 = 数学 from tb union all select 姓名 as 姓名 , 课程 = '物理' , 分数 = 物理 from tb union all select 姓名 as 姓名 , 课程 = '平均分' , 分数 = cast((语文 + 数学 + 物理)*1.0/3 as decimal(18,2)) from tb union all select 姓名 as 姓名 , 课程 = '总分' , 分数 = 语文 + 数学 + 物理 from tb) torder by 姓名 , case 课程 when '语文' then 1 when '数学' then 2 when '物理' then 3 when '平均分' then 4 when '总分' then 5 enddrop table tb
[解决办法]
------------------------------ Author :fredrickhu(小F,向高手学习)-- Date :2012-08-21 11:09:35-- Version:-- Microsoft SQL Server 2008 R2 (RTM) - 10.50.1617.0 (Intel X86) -- Apr 22 2011 11:57:00 -- Copyright (c) Microsoft Corporation-- Enterprise Edition on Windows NT 6.1 <X64> (Build 7600: ) (WOW64)--------------------------------> 测试数据:[项目类型表]if object_id('[项目类型表]') is not null drop table [项目类型表]go create table [项目类型表]([编码] varchar(3),[名称] varchar(7))insert [项目类型表]select '001','ERP项目' union allselect '002','OA项目' union allselect '003','HR项目'--> 测试数据:[项目清单表]if object_id('[项目清单表]') is not null drop table [项目清单表]go create table [项目清单表]([年] int,[月] int,[项目类型] varchar(7),[业务员] varchar(4),[金额] int)insert [项目清单表]select 2012,8,'ERP项目','张三',100000 union allselect 2012,8,'OA项目','张三',50000 union allselect 2012,8,'ERP项目','李四',120000--------------开始查询--------------------------declare @sql varchar(8000)set @sql = 'select b.年,b.月,b.业务员 'select @sql = @sql + ' , max(case a.名称 when ''' + 名称 + ''' then b.金额 else 0 end) [' + 名称 + ']'from (select distinct 名称 from 项目类型表 a) as aset @sql = @sql + ' from 项目类型表 a join 项目清单表 b on a.名称=b.项目类型 group by b.年,b.月,b.业务员'exec(@sql) ----------------结果----------------------------/* 年 月 业务员 ERP项目 HR项目 OA项目----------- ----------- ---- ----------- ----------- -----------2012 8 李四 120000 0 02012 8 张三 100000 0 50000(2 行受影响)*/
[解决办法]
--> 测试数据:[ta]IF OBJECT_ID('[ta]') IS NOT NULL DROP TABLE [ta]GO CREATE TABLE [ta]([编码] VARCHAR(3),[名称] VARCHAR(7))INSERT [ta]SELECT '001','ERP项目' UNION ALLSELECT '002','OA项目' UNION ALLSELECT '003','HR项目'--> 测试数据:[tb]IF OBJECT_ID('[tb]') IS NOT NULL DROP TABLE [tb]GO CREATE TABLE [tb]([年] INT,[月] INT,[项目类型] VARCHAR(7),[业务员] VARCHAR(4),[金额] INT)INSERT [tb]SELECT 2012,8,'ERP项目','张三',100000 UNION ALLSELECT 2012,8,'OA项目','张三',50000 UNION ALLSELECT 2012,8,'ERP项目','李四',120000--------------开始查询--------------------------DECLARE @sql VARCHAR(MAX)SELECT @sql = ISNULL(@sql + ',', '') + QUOTENAME([名称])FROM [ta]EXEC ('SELECT * FROM [tb] PIVOT (MAX([金额]) FOR [项目类型] IN('+@sql+')) t')----------------结果----------------------------/* 年 月 业务员 ERP项目 OA项目 HR项目----------- ----------- ---- ----------- ----------- -----------2012 8 李四 120000 NULL NULL2012 8 张三 100000 50000 NULL(2 行受影响)*/
[解决办法]