学习普通行列转换(2000)

(转至CSDN-爱新觉罗.毓华)
坚持SQL Server的学习, 列转行这个也是比较常见SQL操作
本人愚见, 总结出来具有以下条件的情况下可能会出现此需求: 一个表中某一个列值依赖于该表中两个或多个列(如下表中的成绩依赖于学生和课程),  好像这种情况违反了数据库设计的第一范式(1NF), 哈哈!
今天CSDN上无意看到一个比较全面的列转行, 但是以前没怎么接触心里就有种恐惧,现在系统的学习下,避免以后遇见相同的问题的又束手无策了!
还是开始创建测试环境
 
use  tempdb;
go
if   object_id ( ' tb ' is   not   null
    
drop   table  tb
go
create   table  tb(name  varchar ( 10 ) , course  varchar ( 10 ) , scores  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
 
挺简单的一张表,描述了学生的课程成绩信息,其中有3个字段,依次是姓名,课程,分数
测试数据中有2个学生,分别是张三和李四,而课程有语文,数学,物理3课,查询结果集如下
 
学习普通行列转换(2000)_第1张图片
 
现有这一需求, 将成绩转为行显示,学科为列, 结果如下
 
 
结果改变了什么, 行数改变了,跟学生数量有关,一个学生一行,这里就肯定是用学生姓名来分组了
除姓名外,增加了3列,跟课程数量有关,根据不同的课程创建新列, 这里就是用 "case when"了,代码如下:

 

  • SQL 2000实现

--静态实现

select  name 姓名, 
max ( case  course  when   ' 语文 '   then  scores  end ) 语文,
max ( case  course  when   ' 数学 '   then  scores  end ) 数学,
max ( case  course  when   ' 物理 '   then  scores  end ) 物理
from  tb
group   by  name
 
这里的then后的值都是成绩, 没有区别; 只是条件不同, 属于哪一科的成绩就放在那一列下, 因为是逐行扫描, 每次只有单个成绩, 所以这里的max函数只是为了骗过group分组的幌子, 没有任何意义, 执行查询结果如上所示
 
现将需求稍微小小改变一下, 课程为行学生为列成绩不变在中间, 其实这与上面的一个问题类似, 都是将成绩以行的形式显示, 只是"case when" 和 group不一样而已, 知道原理了, 稍微变通一下, 应该没问题, 哈哈!
 
select  course 课程, 
max ( case  name  when   ' 张三 '   then  scores  end ) 张三,
max ( case  name  when   ' 李四 '   then  scores  end ) 李四
from  tb
group   by  course
 
--动态实现
以上虽然实现了功能, 但是比较死板, 它是静态的, 也就是课程只允许有语文, 数学, 物理, 若增加了其他课程就不行了, 这样我们得动态生成sql语句, 才能根据不同的课程生成不同的sql, 然后执行, 以前从未接触了动态生成sql, 呵呵! 这次看到了才发现了sql编程与开发语言编程有异曲同工之妙, 请看下面动态生成的SQL语句
 
declare   @sql   varchar ( 8000 )
set   @sql   =   ' select name 姓名 '
select   @sql   =   @sql   +   '  , max(case course when  '''   +  course  +   '''  then scores else 0 end)  '   +  course  +   ''
from  ( select   distinct  course  from  tb)  as  a
set   @sql   =   @sql   +   '  from tb group by name '
print   @sql  
  
 
动态拼接后的语句与我们之前手写的结果一样, 然后通过系统存储过程sp_executesql执行, 进行sql查询, 效果一样, 这里用的一个技巧是select @sql变量赋值,  获取去重后所有的科目的集合, 然后循环动态构造case when语句添加到@sql变量后面,  达到我们想要的效果, 这样也能正确执行. 下次再来看看SQL 2005中的实现

你可能感兴趣的:(行列转换)