首页 诗词 字典 板报 句子 名言 友答 励志 学校 网站地图
当前位置: 首页 > 教程频道 > 数据库 > SQL Server >

行列转换SQL

2012-09-05 
求一个行列转换SQL原表项目类型表编码名称001ERP项目002OA项目003HR项目项目清单表年月项目类型业务员金额

求一个行列转换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,项目类型表的数据不能写死在脚本中,要即时查询出来
谢谢 










[解决办法]

SQL code
/*标题:普通行列转换(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 


[解决办法]

SQL code
------------------------------ 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 行受影响)*/
[解决办法]
SQL code
--> 测试数据:[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 行受影响)*/
[解决办法]
探讨
引用:
引用:

引用:
动态还是静态的?


我重新看了一下实际的问题,在某个时间点是静态的。当然客户有可能修改,但是客户这样做,相关的功能不可避免该跟着变动。先按静态的来处理吧

那你还是写成动态的吧,以后不需要改


试试5楼,短小精悍



NULL值能改成0吗。

另外,我想把这个结果记录下来(实体表、临……

热点排行