所以,觉得有必要记录下来,这样以后再次碰到这类问题,也能从中获取解答的思路。
下面的几个问题,都是动态行转列的问题。
1、数据查询,行转列的问题。
http://bbs.csdn.net/topics/390621630?page=1#post-395855019
根据数据查询得到如下数据表(tab): 班级 学号 姓名 科目 得分 班排名 校排名 标准分 ClassName Code Name SubjectName TotalScore Cla***ank SchoolRank TValue 201班 101 张三 语文 95 1 1 700 201班 102 李四 语文 83 2 3 600 202班 201 张飞 语文 85 1 2 700 202班 202 赵云 语文 75 2 4 600 201班 101 张三 数学 83 2 2 600 201班 102 李四 数学 85 1 3 700 202班 201 张飞 数学 95 1 1 700 202班 202 赵云 数学 80 2 4 600 需要得到如下数据: 班级 学号 姓名 语文 得分 班排名 校排名 标准分 数学 得分 班排名 校排名 标准分 201班 101 张三 语文 95 1 1 700 数学 83 2 2 600 201班 102 李四 语文 83 2 3 600 数学 85 1 3 700 202班 201 张飞 语文 85 1 2 700 数学 95 1 1 700 202班 202 赵云 语文 75 2 4 600 数学 80 2 4 600 真心求SQL,或者实现方法。 科目是动态的。能实现静态转换也行。 真心谢谢。
我的解法:
if object_id('tab') is not null drop table tab go create table tab ( [班级] varchar(9),[学号] varchar(4),[姓名] varchar(4), [科目] varchar(11),[得分] varchar(10),[班排名] varchar(9), [校排名] varchar(10),[标准分] varchar(6) ) insert tab select '201班','101','张三','语文','95','1','1','700' union all select '201班','102','李四','语文','83','2','3','600' union all select '202班','201','张飞','语文','85','1','2','700' union all select '202班','202','赵云','语文','75','2','4','600' union all select '201班','101','张三','数学','83','2','2','600' union all select '201班','102','李四','数学','85','1','3','700' union all select '202班','201','张飞','数学','95','1','1','700' union all select '202班','202','赵云','数学','80','2','4','600' --------------开始查询-------------------------- declare @sql nvarchar(3000); set @sql = ''; select @sql = @sql + ',min(case when 科目=''' + 科目 + ''' then 科目 else null end) as ['+科目+ ']'+ ',min(case when 科目=''' + 科目 + ''' then 得分 else null end) as 得分' + ',min(case when 科目=''' + 科目 + ''' then 班排名 else null end) as 班排名'+ ',min(case when 科目=''' + 科目 + ''' then 校排名 else null end) as 校排名'+ ',min(case when 科目=''' + 科目 + ''' then 标准分 else null end) as 标准分' from tab group by 科目 order by 科目 desc select @sql = 'select 班级,学号,姓名'+@sql + ' from tab group by 班级,学号,姓名' select @sql exec(@sql) /* 班级 学号 姓名 语文 得分 班排名 校排名 标准分 数学 得分 班排名 校排名 标准分 --------- ---- ---- ----------- ---------- --------- ---------- ------ ----------- ---------- --------- ---------- ------ 201班 101 张三 语文 95 1 1 700 数学 83 2 2 600 201班 102 李四 语文 83 2 3 600 数学 85 1 3 700 202班 201 张飞 语文 85 1 2 700 数学 95 1 1 700 202班 202 赵云 语文 75 2 4 600 数学 80 2 4 600 警告: 聚合或其他 SET 操作消除了 Null 值。 */
select 班级,学号,姓名, min(case when 科目='语文' then 科目 else null end) as [语文], min(case when 科目='语文' then 得分 else null end) as 得分, min(case when 科目='语文' then 班排名 else null end) as 班排名, min(case when 科目='语文' then 校排名 else null end) as 校排名, min(case when 科目='语文' then 标准分 else null end) as 标准分, min(case when 科目='数学' then 科目 else null end) as [数学], min(case when 科目='数学' then 得分 else null end) as 得分, min(case when 科目='数学' then 班排名 else null end) as 班排名, min(case when 科目='数学' then 校排名 else null end) as 校排名, min(case when 科目='数学' then 标准分 else null end) as 标准分 from tab group by 班级,学号,姓名
现在要变为:
日期 城市 气象 最高 最低 -------------------------------------------------------------- 2013-10 合肥 多云 32 20 2013-10 芜湖 雨 35 20 2013-11 合肥 晴 30 20 2013-11 芜湖 晴 25 20 可以的话尽量写成动态,因为不只两个城市 如果我的第一个表是这样呢: 日期 合肥 F3 F4 芜湖 F6 F7 北京 F9 F10 福州 F12 F13 ------------------------------------------------------------------------------------------------ NULL 气象 最高 最低 气象 最高 最低 气象 最高 最低 气象 最高 最低 2013-10 多云 32 20 雨 35 20 晴 32 20 多云 25 20 2013-11 晴 30 20 晴 25 20 雨 31 21 晴 25 21 你能否写一个循环语句,首先城市的数量是(最后一个列名的阿拉伯数字-1)/3,然后再作判断写出像你第一个贴得出的结果集。if object_id('tb') is not null drop table tb go create table tb ( 日期 varchar(15), 合肥 varchar(10), F3 varchar(10), F4 varchar(10), 芜湖 varchar(10), F6 varchar(10), F7 varchar(10), 北京 varchar(10), F9 varchar(10), F10 varchar(10), 福州 varchar(10), F12 varchar(10), F13 varchar(10) ) insert into tb select NULL,'气象', '最高','最低','气象','最高','最低','气象','最高','最低' ,'气象','最高','最低' union all select '2013-10','多云', '32' ,'20', '雨','35', '20', '晴','32','20' , '多云','25','20' union all select '2013-11','晴', '30','20','晴','25', '20', '雨','31','21','晴','25' , '21' go declare @tb_name nvarchar(100); declare @t table(tb_name nvarchar(100),column_name nvarchar(100),column_id int) declare @i int declare @count int declare @sql nvarchar(max); --这里的表为 tb,需要换成你自己的表名 set @tb_name = 'tb' insert into @t select t.name , c.name, c.column_id from sys.tables t inner join sys.columns c on t.object_id = c.object_id where t.name = @tb_name set @i = 2 set @count = (select count(*) from @t) set @sql =''; while @i < @count begin set @sql = @sql + 'union all select 日期,''' + (select column_name from @t where column_id = @i) + ''' as 城市,' + (select column_name from @t where column_id = @i) + ' as 气象,' + (select column_name from @t where column_id = @i+1) + ' as 最高,'+ (select column_name from @t where column_id = @i+1+1) + ' as 最低 ' + ' from ' + (select distinct tb_name from @t) + ' where 日期 is not null ' set @i = @i + 3 end select @sql = stuff(@sql,1,len('union all'),'') --select @sql exec(@sql) /* 日期 城市 气象 最高 最低 --------------- ---- ---------- ---------- ---------- 2013-10 合肥 多云 32 20 2013-11 合肥 晴 30 20 2013-10 芜湖 雨 35 20 2013-11 芜湖 晴 25 20 2013-10 北京 晴 32 20 2013-11 北京 雨 31 21 2013-10 福州 多云 25 20 2013-11 福州 晴 25 21 */
select 日期,'合肥' as 城市,合肥 as 气象,F3 as 最高,F4 as 最低 from tb where 日期 is not null union all select 日期,'芜湖' as 城市,芜湖 as 气象,F6 as 最高,F7 as 最低 from tb where 日期 is not null union all select 日期,'北京' as 城市,北京 as 气象,F9 as 最高,F10 as 最低 from tb where 日期 is not null union all select 日期,'福州' as 城市,福州 as 气象,F12 as 最高,F13 as 最低 from tb where 日期 is not null
3、sql经典行转列问题,外加点小难度。
http://bbs.csdn.net/topics/390636728
脚本如下:
create table tab ( NumID int, SkuID int, Stock int ) go declare @i int set @i=1 while @i<23 begin insert into tab (NumID,SkuID,Stock) values ('23940',3982+@i,3+@i) set @i=@i+1 end declare @k int set @k=1 while @k<4 begin insert into tab (NumID,SkuID,Stock) values ('33950',32+@k,3+@k) set @k=@k+1 end declare @n int set @n=1 while @n<2 begin insert into tab (NumID,SkuID,Stock) values ('36951',52+@n,3+@n) set @n=@n+1 end求结果如下,注意:相同NumID中超过20条记录以后行转列过程中需要折分成两条记录:
NumID Sku_Stock ------------------------- 23940 3983:4;3984:5;3985:6;3986:7;3987:8;3988:9;3989:10;3990:11;3991:12;3992:13;3993:14;3994:15;3995:16;3996:17;3997:18;3998:19;3999:20;4000:21;4001:22;4002:23 23940 4003:24;4004:25 33950 33:4;34:5;35:6 36951 53:4我的解法:
;WITH t AS ( SELECT *, (select count(*) from tab t2 where t2.numid = t1.numid and t2.skuid <=t1.skuid) as rownum FROM tab t1 ) ,tt AS ( select NumID,SkuID,Stock,rownum, (rownum -1) / 20 as rownum_group from t ) SELECT NumID, STUFF( ( SELECT ';'+cast(SkuID as varchar)+':'+cast(Stock as varchar) FROM tt tt2 WHERE tt2.NumID=tt1.NumID AND tt2.rownum_group = tt1.rownum_group FOR XML PATH('') ), 1,1,'' ) as sku_stock FROM tt tt1 GROUP BY NumID,rownum_group /* NumID sku_stock 23940 3983:4;3984:5;3985:6;3986:7;3987:8;3988:9;3989:10;3990:11;3991:12;3992:13;3993:14;3994:15;3995:16;3996:17;3997:18;3998:19;3999:20;4000:21;4001:22;4002:23 23940 4003:24;4004:25 33950 33:4;34:5;35:6 36951 53:4 */