登录  
 加关注
   显示下一条  |  关闭
温馨提示!由于新浪微博认证机制调整,您的新浪微博帐号绑定已过期,请重新绑定!立即重新绑定新浪微博》  |  关闭

Perfect-World

以無法為有法,以無限為有限!

 
 
 

日志

 
 

记录由行变成列的SQL语句怎么写?  

2007-03-05 13:09:46|  分类: DBA |  标签: |举报 |字号 订阅

  下载LOFTER 我的照片书  |

假设有一下表:  
  字段1       字段2  
  a             b1  
  a             b2  
  a             b3  
  c             d1  
  c             d2   
也就是说存在一对多的关系,怎么用SQL语句把他变成杭的关系,比如变成:  
  字段1      字段21       字段22       字段23       字段24          字段25  
  a             b1          b2           b3           0               0  
  c             d1          d2           0            0               0  
--------------------------------------------------------------------------------------------
  1:   列转为行:  
  eg1:  
  Create   table   test   (name   char(10),km   char(10),cj   int)  
  go  
  insert   test   values('张三','语文',80)  
  insert   test   values('张三','数学',86)  
  insert   test   values('张三','英语',75)  
  insert   test   values('李四','语文',78)  
  insert   test   values('李四','数学',85)  
  insert   test   values('李四','英语',78)  
  想变成  
  姓名       语文       数学       英语  
  张三       80           86           75  
  李四       78           85           78  
  declare   @sql   varchar(8000)  
  set   @sql   =   'select   name'  
  select @sql = @sql + ',sum(case km when'''+km+''' then cj end) ['+km+']' from (select   distinct   km   from   test)   as   a  
  select   @sql   =   @sql+'   from   test   group   by   name'  
  exec(@sql)  
  drop   table   test  
 eg2:  
  有表A,  
    id   pid  
    1       1  
    1       2  
    1       3  
    2       1  
    2       2  
    3       1  
  如何化成表B:  
    id   pid  
    1     1,2,3  
    2     1,2  
    3     1  
  或者是从表B变成A(不要用游标)  

  --1.创建一个合并的函数  
  create   function   fmerg(@id   int)  
  returns   varchar(8000)  
  as  
  begin  
  declare   @str   varchar(8000)  
  set   @str=''  
  select   @str=@str+','+cast(pid   as   varchar)   from   表A   where  
  set   @str=right(@str,len(@str)-1)  
  return(@str)  
  End  
  go  
  --调用自定义函数得到结果  
  select   distinct   id,dbo.fmerg(id)   from   表A  
 --=========================================  
    2:  
  /***********           行转列       *****************/  
  测试:  
  create   table   t1   (a   int,b   int,c   int,d   int,e   int,f   int,g   int,h   int)  
  insert   t1   values(15,   9,   1,   0,   1,   2,   2,   0)  
  declare   @   varchar(8000)  
  set   @=''  
  select @=@+rtrim(name)+'from t1 union all select'from syscolumns where
  t1')    
  set   @=left(@,len(@)-len('   from   t1   union   all   select   '))  
  --print   @  
  exec('select   '+@+'   from   t1')  
   
  a                        
  -----------    
  15  
  9  
  1  
  0  
  1  
  2  
  2  
  0  

3:
  将结果矩阵转置
  if exists (select*from sysobjects where proc_sky_blue') and xtype ='P')
  drop proc proc_sky_blue
  go
  create proc proc_sky_blue (@tablename varchar(200))  
  as
  begin
      set nocount on  
      declare @col nvarchar(256)  
      declare @makesql nvarchar(4000)  
      declare @insertsql nvarchar(4000)  
      declare @caculatesql nvarchar(400)  
      declare @count int  
      declare @i int  
      create table #tmp (colname nvarchar(20))  
      select @caculatesql = 'select  @count=count(1) from'+ @tablename  
      exec sp_executesql @caculatesql, N'@count int output',@count output  
      if @count >=1024  
      begin  
          raiserror('表的行数太多了,我转不了',16,1)  
      end  
      else  
      begin  
          select @i=0  
          while @count >0  
          begin  
  select @i=@i+1  
  select @makesql='alter table #tmp add col'+convert(varchar(20),@i)+'int' exec(@makesql)  
  select @count=@count-1          
          end  
          declare my_cursor cursor for    
          select name from syscolumns where order by colid  
          open   my_cursor  
          fetch   next   from   my_cursor   into   @col  
          while   @@fetch_status   =   0  
          begin  
          select @makesql='select @insertsql= @insertsql + convert(varchar(4),'+@col+')
                 +'',''   from   '   +@tablename  
              select   @insertsql   =N'insert   #tmp   values   ('''+@col+   ''','  
     execute sp_executesql @makesql,N'@insertsql nvarchar(4000) output',@insertsql output  
              select   @insertsql   =   left(@insertsql,len(@insertsql)-1)   +')'  
              exec(@insertsql)  
              fetch   next   from   my_cursor   into   @col  
          end  
          close   my_cursor  
          deallocate   my_cursor  
          select   *   from   #tmp  
          set   nocount   off  
      end  
  end  
  go  
  ----------------分析  
  declare   @tablename   varchar(200)  
  set   @tablename='table1'  
  begin  
      set   nocount   on  
      declare   @col   nvarchar(256)  
      declare   @makesql   nvarchar(4000)  
      declare   @insertsql   nvarchar(4000)  
      declare   @caculatesql   nvarchar(400)  
      declare   @count   int  
      declare   @i   int  
      create   table   #tmp   (colname   nvarchar(20))  
      select   @caculatesql   =   'select   @count=count(1)   from   '   +   @tablename  
      exec   sp_executesql   @caculatesql,   N'@count   int   output',@count   output  
      if   @count   >=1024  
      begin  
          raiserror('表的行数太多了,我转不了',16,1)  
      end  
      else  
      begin  
          select   @i=0  
          while   @count   >0  
          begin  
              select   @i=@i+1  
       select @makesql = 'alter table #tmp add col'+convert(varchar(20),@i)+'int'  
              exec(@makesql)  
              select   @count=@count-1          
          end  
          declare   my_cursor   cursor   for    
          select name from syscolumns where order by colid  
          open   my_cursor  
          fetch   next   from   my_cursor   into   @col  
          while   @@fetch_status   =   0  
          begin  
     select @makesql='select @insertsql=@insertsql+convert(varchar(4),'+@col+')+'',''from'+
     @tablename  
     select   @insertsql   =N'insert   #tmp   values   ('''+@col+   ''','  
     execute sp_executesql @makesql,N'@insertsql nvarchar(4000) output',@insertsql output  
              select   @insertsql   =   left(@insertsql,len(@insertsql)-1)   +')'  
              select   @insertsql  
              --exec(@insertsql)  
              fetch   next   from   my_cursor   into   @col  
          end  
          close   my_cursor  
          deallocate   my_cursor  
          select   *   from   #tmp  
          set   nocount   off  
          drop   table   #tmp  
      end  
  end   

-------------------------------------------------------------------------------------------------------------------------------------

主要应用case语句来解决行转列的问题

行转列问题主要分为两类

1)简单的行转列问题:

示例表:

id  sid           course  result

1   2005001 语文     80.0
2   2005001 数学     90.0
3   2005001 英语     80.0
4   2005002 语文     56.0
5   2005002 数学     69.0
6   2005002 英语     89.0

执行

select sid,语文=isnull(sum(case course when '语文' then result end),0),
   数学=isnull(sum(case course when '数学' then result end),0),
   英语=isnull(sum(case course when '英语' then result end),0)
   from result
   group by sid
   order by sid

 

得出结果

sid           语文 数学 英语

2005001 80.0  90.0  80.0
2005002 56.0  69.0  89.0

 

2)较为复杂的行转列

表1:course

id name

1 语文
2 数学
3 英语


表2:result

id sid          course  result

1 2005001 语文      80.0
2 2005001 数学      90.0
3 2005001 英语      80.0
4 2005002 语文      56.0
5 2005002 数学      69.0
6 2005002 英语      89.0

 

declare @sql varchar(8000)
set @sql='select sid'
select @sql=@sql+','+course.name+'=isnull(sum(case course when '''+course.name+''' then result end),0)'
 from course order by id
set @sql=@sql+' from result group by sid order by sid'
print @sql
exec(@sql)

 

得出结果

sid           语文 数学 英语

2005001 80.0  90.0  80.0
2005002 56.0  69.0  89.0

  评论这张
 
阅读(2437)| 评论(1)

历史上的今天

评论

<#--最新日志,群博日志--> <#--推荐日志--> <#--引用记录--> <#--博主推荐--> <#--随机阅读--> <#--首页推荐--> <#--历史上的今天--> <#--被推荐日志--> <#--上一篇,下一篇--> <#-- 热度 --> <#-- 网易新闻广告 --> <#--右边模块结构--> <#--评论模块结构--> <#--引用模块结构--> <#--博主发起的投票-->
 
 
 
 
 
 
 
 
 
 
 
 
 
 

页脚

网易公司版权所有 ©1997-2018