SQL中几种行变列的情况

来源:互联网 发布:曾志豪 知乎 编辑:程序博客网 时间:2024/04/30 03:31

/*有三个数据库表, 一个是学生表S(SNO,SNAME),字段分别表示学号,姓名; 一个是课程表C(CNO,CNAME),字段分别表示课程号,课程名称; 一个是成绩表T(SNO,CNO,SCORE),字段分别表示学号,课程号,该学生该课程成绩。

现在要实现这个表:

姓名 语文 数学 英语 物理 化学 ... 张三  分数 分数 分数 分数 分数  李四 分数 分数 分数 分数 分数 王五 分数 分数 分数 分数 分数 ...

*/

T-SQL

object_id('s'is not null drop table s if object_id('c'is not null drop table c if object_id('t'is not null drop table t create table S(sno int,sname varchar(300)) create table c(cno int,cname varchar(300)) create table t(sno int,cno int,score int) insert   into   S(sno,sname)  select   1,'张三'  union    select   2,'李四'  union  select   3,'王五'  union  select   4,'甲六'  insert   into   c(cno,cname)  select   1,'语文'  union    select   2,'数学'  union  select   3,'英语'  union    select   4,'物理'  union    select   5,'化学'  union  select   6,'历史'  union  select   7,'历史'  insert   into   t(SNO,CNO,score)  select   1,1,80  union  select   1,2,70  union  select   1,3,50  union  select   1,4,60  union  select   1,5,90  union  select   1,6,60  union  select   2,1,41  union  select   2,2,42  union  select   2,3,53  union  select   2,4,64  union  select   3,1,43  union  select   3,2,44  union  select   3,3,55  union  select   3,4,66  /*使用动态SQL语句*/ declare   @abc   varchar(3000set   @abc   =   ''  select   @abc   =   @abc   +   ',min(   case     when   cno   =   '+  cast(cno   as   varchar(8))   +'   then     score     end   )   as   '''+cname+ '''' from   c  declare   @sql     varchar(3000set   @sql   =   'select   (select   sname     from   S  where S.sno=   T.sno   )   as   sname     '+@abc   +'   from   T   group   by   sno'  exec   (@sql /* 不使用动态SQL语句*/ select sname 姓名,  max(yw) 语文, max(sx) 数学, max(yy) 英语, max(wl) 物理, max(hx) 化学,  max(ls) 历史 from (  select sname ,(case when cname='语文' then score  end) yw,  (case when cname='数学' then score end) sx, (case when cname='英语' then score  end) yy,  (case when cname='物理' then score  end) wl, (case when cname='化学' then score  end) hx, (case when cname='历史' then score  end) ls      from t left join s on t.sno=s.sno left join c on t.cno=c.cno   ) tmp   group by sname

 

有如图A所示的表stat,表的内容为各个班级拥有水果的数量,要求将表stat的查询结果以图B的形式显示。

class        fruit     amount ----------------------------- class a      apple     30 class a      pear      15 class b      apple     40 class b      pear      20   图 A

class    apple_amount pear_amount ---------------------------- class a      30        15 class b      40        20   图 B

T-SQL

 

create table stat(class varchar(30), fruit varchar(30), amount int) insert into stat (class,fruit,amount)  select 'class a''apple'30 union select 'class a''pear'15 union select 'class b''apple'40 union select 'class b''pear'20 union select 'class a','apple',11  union   select 'class b','apple',12 select * from stat select class, sum(apple_amount) apple_amount, sum(pear_amount) pear_amount   from (     select class, (case when fruit='apple' then amount else 0 endas apple_amount, (case when fruit='pear' then amount else 0 endas pear_amount     from stat   ) tmp   group by class

 

PL/SQL

 

 create table stat(class varchar2(30), fruit varchar2(30), amount number(10));  insert into stat(class, fruit, amount)  values('class a''apple'30);  insert into stat(class, fruit, amount)  values('class a''pear'15);  insert into stat(class, fruit, amount)  values('class b''apple'40);  insert into stat(class, fruit, amount)  values('class b''pear'20);  commit select class, sum(apple_amount) apple_amount, sum(pear_amount) pear_amount   from (     select class, decode(fruit, 'apple', amount, 0) apple_amount, decode(fruit, 'pear', amount, 0) pear_amount     from stat   )   group by class  

 

存储过程

/*范例表      create   table   表1   (      號數   char(10),        成績   integer,        科目   char(10)   )        insert   into   表1   select   '1',60,'数学'        union   select   '1',43,'物理'        union   select   '1',100,'语文'        union   select   '2',87,'语文'        union   select   '2',99,'数学'        union   select   '2',89,'物理'        union   select   '2',87,'语文'        */      Create   procedure   RowToColumn          @Table   varchar(30),                     --表名          @MasterField   varchar(30), --待转名称列名   char字段          @SlaveField   varchar(30), --待转数据列名   int型字段          @GroupID   varchar(30--分组ID          as      --调用方法   RowToColumn   '表1','科目','成績','號數'        begin          DECLARE   @mSQL   VARCHAR(8000)              set   @msql   =   'DECLARE   @SQL   VARCHAR(8000)'              set   @msql   =   @msql   +   '   set   @SQL=   ''select   '   +   @GroupID   +   ''''              set   @msql   =   @msql   +   '   SELECT   @SQL=   @SQL+'',max(CASE   WHEN   '   +              @MasterField   +   '=''''''+'   +   @MasterField   +   '+''''''   then     '   +   @SlaveField   +                  '   else   0   end   )[''+'   +   @MasterField   +   '+'']''   from(select   distinct   '   +                  @MasterField   +   '   from   '   +   @Table   +   ')   a'              set   @msql   =   @msql   +   '   SET   @SQL=@SQL+   ''   from   '   +   @Table   +   '   group   by   '   +                  @GroupID   +   ''''              set   @msql   =   @msql   +   '   exec(@SQL)'              exec(@msql)      end     

 

分组行转列

/*1. 表格A原始数据如下:*/ CREATE TABLE [dbo].[A] (  [C1] [varchar] (50) COLLATE Chinese_PRC_CS_AS NULL ,  [C2] [varchar] (50) COLLATE Chinese_PRC_CS_AS NULL ,  [C3] [varchar] (50) COLLATE Chinese_PRC_CS_AS NULL ,  [C4] [varchar] (50) COLLATE Chinese_PRC_CS_AS NULL  insert into A ('95533','SZ','44','123000') insert into A ('95566','SZ','44','233300') insert into A ('95588','GZ','44','4566') insert into A ('95599','GZ','44','456666') insert into A ('95533','ZH','44','333333') insert into A ('95577','DG','44','555555') insert into A ('95588','ST','44','44444' /*2. 分组行变列 处理数据:*/ DECLARE @SQL VARCHAR(4000SET @SQL='SELECT C2'  SELECT @SQL= @SQL+ ',max(CASE WHEN C1 = ''' + C1 + ''' THEN C4 ELSE 0 END) ['+C1+']' FROM (SELECT DISTINCT C1 FROM A) TAB SET @SQL=@SQL+ ' FROM A GROUP BY C2'  EXEC (@SQL /*得到如下结果: */ C2 95533 95566 95577 95588 95599 -------------------------------------------- DG 0 0 555555 0 0  GZ 0 0 0 4566 456666  ST 0 0 0 44444 0  SZ 123000 233300 0 0 0  ZH 333333 0 0 0 0  OK, 分组就这样完成了. 参考经典实例:  /*   实例一 create table t (id int identity,name varchar(10),code int) insert t values('人口',20) insert t values('经济',12) insert t values('文化',15) insert t values('土地',45)  declare @sql varchar(1000) set @sql = '' select @sql = @sql+name+'=max(case when name='''+name+''' then code else null end),' from t --print @sql  set @sql = left(@sql,len(@sql) - 1) set @sql = 'select [姓名]=''年龄'', '+@sql+' from t' exec (@sql) --drop table t  实例二  create   table   #(a   varchar(100),b   int)      insert   #   values('aa',11)      insert   #   values('bb',1)      insert   #   values('aa',45)      insert   #   values('cc',81)      insert   #   values('a',11)      insert   #   values('aay',561)      insert   #   values('a',14)           declare   @sql   varchar(8000)      set   @sql   =   'select   '      select   @sql   =   @sql   +   'sum(case   a   when   '''+a+'''                                                            then   b   else   0   end)   '+a+'的数量,'          from   (select   distinct   a   from   #)   as   a           select   @sql   =   left(@sql,len(@sql)-1)   +   '   from   #'           exec(@sql)         --  drop   table   #  */ 
--行列互转/******************************************************************************************************************************************************以学生成绩为例子,比较形象易懂整理人:中国风(Roy)日期:2008.06.06******************************************************************************************************************************************************/--1、行互列--> --> (Roy)生成測試數據 if not object_id('Class') is null    drop table ClassGoCreate table Class([Student] nvarchar(2),[Course] nvarchar(2),[Score] int)Insert Classselect N'张三',N'语文',78 union allselect N'张三',N'数学',87 union allselect N'张三',N'英语',82 union allselect N'张三',N'物理',90 union allselect N'李四',N'语文',65 union allselect N'李四',N'数学',77 union allselect N'李四',N'英语',65 union allselect N'李四',N'物理',85 Go--2000方法:动态:declare @s nvarchar(4000)set @s=''Select     @s=@s+','+quotename([Course])+'=max(case when [Course]='+quotename([Course],'''')+' then [Score] else 0 end)'from Class group by[Course]exec('select [Student]'+@s+' from Class group by [Student]')生成静态:select     [Student],    [数学]=max(case when [Course]='数学' then [Score] else 0 end),    [物理]=max(case when [Course]='物理' then [Score] else 0 end),    [英语]=max(case when [Course]='英语' then [Score] else 0 end),    [语文]=max(case when [Course]='语文' then [Score] else 0 end) from     Class group by [Student]GO动态:declare @s nvarchar(4000)Select     @s=isnull(@s+',','')+quotename([Course]) from Class group by[Course]exec('select * from Class pivot (max([Score]) for [Course] in('+@s+'))b')生成静态:select * from     Class pivot     (max([Score]) for [Course] in([数学],[物理],[英语],[语文]))b生成格式:/*Student 数学          物理          英语          语文------- ----------- ----------- ----------- -----------李四      77          85          65          65张三      87          90          82          78(2 行受影响)*/------------------------------------------------------------------------------------------go--加上总成绩(学科平均分)--2000方法:动态:declare @s nvarchar(4000)set @s=''Select     @s=@s+','+quotename([Course])+'=max(case when [Course]='+quotename([Course],'''')+' then [Score] else 0 end)'from Class group by[Course]exec('select [Student]'+@s+',[总成绩]=sum([Score])  from Class group by [Student]')--加多一列(学科平均分用avg([Score]))生成动态:select     [Student],    [数学]=max(case when [Course]='数学' then [Score] else 0 end),    [物理]=max(case when [Course]='物理' then [Score] else 0 end),    [英语]=max(case when [Course]='英语' then [Score] else 0 end),    [语文]=max(case when [Course]='语文' then [Score] else 0 end),    [总成绩]=sum([Score]) --加多一列(学科平均分用avg([Score]))from     Class group by [Student]go--2005方法:动态:declare @s nvarchar(4000)Select     @s=isnull(@s+',','')+quotename([Course]) from Class group by[Course] --isnull(@s+',','') 去掉字符串@s中第一个逗号exec('select [Student],'+@s+',[总成绩] from (select *,[总成绩]=sum([Score])over(partition by [Student]) from Class) a pivot (max([Score]) for [Course] in('+@s+'))b ')生成静态:select     [Student],[数学],[物理],[英语],[语文],[总成绩] from     (select *,[总成绩]=sum([Score])over(partition by [Student]) from Class) a --平均分时用avg([Score])pivot     (max([Score]) for [Course] in([数学],[物理],[英语],[语文]))b 生成格式:/*Student 数学          物理          英语          语文          总成绩------- ----------- ----------- ----------- ----------- -----------李四      77          85          65          65          292张三      87          90          82          78          337(2 行受影响)*/go--2、列转行--> --> (Roy)生成測試數據 if not object_id('Class') is null    drop table ClassGoCreate table Class([Student] nvarchar(2),[数学] int,[物理] int,[英语] int,[语文] int)Insert Classselect N'李四',77,85,65,65 union allselect N'张三',87,90,82,78Go--2000:动态:declare @s nvarchar(4000)select @s=isnull(@s+' union all ','')+'select [Student],[Course]='+quotename(Name,'''')--isnull(@s+' union all ','') 去掉字符串@s中第一个union all+',[Score]='+quotename(Name)+' from Class'from syscolumns where ID=object_id('Class') and Name not in('Student')--排除不转换的列order by Colidexec('select * from ('+@s+')t order by [Student],[Course]')--增加一个排序生成静态:select * from (select [Student],[Course]='数学',[Score]=[数学] from Class union all select [Student],[Course]='物理',[Score]=[物理] from Class union all select [Student],[Course]='英语',[Score]=[英语] from Class union all select [Student],[Course]='语文',[Score]=[语文] from Class)t order by [Student],[Course]go--2005:动态:declare @s nvarchar(4000)select @s=isnull(@s+',','')+quotename(Name)from syscolumns where ID=object_id('Class') and Name not in('Student') order by Colidexec('select Student,[Course],[Score] from Class unpivot ([Score] for [Course] in('+@s+'))b')goselect     Student,[Course],[Score] from     Class unpivot     ([Score] for [Course] in([数学],[物理],[英语],[语文]))b生成格式:/*Student Course Score------- ------- -----------李四      数学      77李四      物理      85李四      英语      65李四      语文      65张三      数学      87张三      物理      90张三      英语      82张三      语文      78(8 行受影响)*/