--行列互换例子:
--交叉表处理的通用存储过程
create proc p_qry
@tbname sysname, --要处理的表名
@groupfd sysname, --分组的字段
@mergfd sysname --合并的字段名
as
exec('select a=cast('+@groupfd+' as varchar)
,b=cast('+@mergfd+' as varchar)
,r=cast('''' as varchar(8000)) 
into #t from '+@tbname+'
declare @a varchar(8000),@r varchar(8000)
update #t set @r=case @a when a then @r+'',''+b else b end
,r=@r,@a=a
select '+@groupfd+'=a,'+@mergfd+'=max(r) from #t group by a
')
go--调用示例
exec p_qry 'syscolumns','id','name'
go使用交叉表:
CREATE PROCEDURE RobinCrossTable --交叉表生成器
--(Select Distinct SuppCode As SCode,MCode,PurQtyRate As Rate
--        From MtSPM A Inner Join MtSPD B On A.ID=B.MtSuppPriceM_ID
--                     Inner Join Suppliers C On A.Supp_ID=C.ID
--        Where A.Active_KID=120 And AduitPass=1) D
@vSourceTAB As Varchar(2000), --数据来源表,可以为表,视图,或者SQL语句(要用括号以及别名:如上注释段)
@vGroupbyField As Varchar(50), --被selct Group By 要显示出来的,可以多个字段(记录可以有空值)
@vTransFormCol As Varchar(50), --交叉表中的合计等函数计算值的字段
@vFunction As Varchar(50)=' Sum', --默认值,交叉表中的函数,也可以是' 2*Sum'的计算公式
@vPivotCol As Varchar(50), --要转换成列的字段,唯一列,可以是表达式'Field1+Field2'(记录可以有空值)
@vStrWhere As Varchar(500) =Null, --Where 约束条件,可以为空
@vSumstr As Varchar(50)         --最后一列的合计总和
AS
--重要提示:@StrSql的Largest size allowed Is 8000,因此尽量将少的字段内容转换为列
Declare @StrSql As Varchar(8000) --//总的SQL语句
Declare @StrSum As Varchar(3000) --//列合计
Declare @pCols As Varchar(100)
Declare @StrWhere As Varchar(500)
Execute('Declare CursorCross Cursor For  
          Select Distinct ' + @vPivotCol + ' From ' +@vSourceTAB +' Order By ' + @vPivotCol + ' For Read only ')
Begin
  Set Nocount On
  Set @StrSql =''
  Set @StrSum=''
  Set @pCols=''
  IF Rtrim(Ltrim(IsNull(@vStrWhere,''))) <> ''
  Begin
    Set @StrWhere=' Where ' + @vStrWhere + ' '
  End
Else
  Set @StrWhere=''
  Open CursorCross
  While (0=0)
  Begin
    Fetch Next From CursorCross Into @pCols
    IF (@@Fetch_Status<>0) Break
    IF @pCols Is  Null --//不为空值,
    Set @pCols='Null'
    --为了防止新创建的列的标题名称,与@vGroupbyField中的字段重名,
    --新创建的列的标题名称都增加前缀[@vGroupbyField.新创建的列的标题名称]
--因Sql长度限制Max=8000,由源数据控制字段值不能为Null,因此这里不再检验值是否为Null
    Set @StrSql=@StrSql +',' + @vFunction +
        '(Case '+@vPivotCol+' When ''' + @pCols+ ''' Then '+@vTransFormCol +' Else 0 End) As '+ 
        '['+@pCols+']'
--    print @StrSql
--因长度限制,不计算列间之和
--    Set @StrSum=@StrSum + '+IsNull(A.' + '['+Left(@vPivotCol,1)+@pCols+']' +',0)'
  End
  Set  @StrSql = @StrSql+','+@vFunction+'('+@vTransFormCol+') as '+@vSumstr
  Set  @StrSql = ' Select ' + @vGroupByField + ' ' +@StrSql + ' From ' +@vSourceTAB+ ' ' + @StrWhere +
                 ' Group By ' + @vGroupByField 
  --列向合计 为字段名'TotalSum'
--  Set @StrSql ='Select A.*,(0' +@StrSum + ') As TotalSum From (' + @StrSql  +') As A'
  Set @StrSql ='Select A.* From ('+@StrSql+') As A'
  Execute(@StrSql)
  IF @@Error <>0
    Return @@Error
  Close CursorCross
  Deallocate CursorCross
  Return 0
End
GO

解决方案 »

  1.   

    /*范例表
    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','科目','成績','號數'
    --by jinjazz  环境 SQLServer2000
    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
    反过来,列转行就简单了..直接union即可
    create table tt (color char(10),   S integer,   M  integer,  L integer)
    insert into tt 
    select  'RED',     0 ,  2,   3
    union select 
      'WHI',     1,   1,   2
    union select 
      'BLK',     3,   3,   2select * from ttselect color,size='s',qty=s from tt
    union
    select color,size='m',qty=m from tt
    union
    select color,size='l',qty=l from tt
    order by colordrop table tt
      

  2.   

    create proc p_qry
    @tbname sysname, --要处理的表名
    @groupfd sysname, --分组的字段
    @mergfd sysname --合并的字段名
    as
    exec('select a=cast('+@groupfd+' as varchar)
    ,b=cast('+@mergfd+' as varchar)
    ,r=cast('''' as varchar(8000)) 
    into #t from '+@tbname+'
    declare @a varchar(8000),@r varchar(8000)
    update #t set @r=case @a when a then @r+'',''+b else b end
    ,r=@r,@a=a
    select '+@groupfd+'=a,'+@mergfd+'=max(r) from #t group by a
    ')
    go
      

  3.   

    zlp321002(想在北京找份工作!) : 试完了,你的后面的那过程RobinCrossTable 可以转换,但最后统计列的数据不准确,经常出现有出一些数据无法求和,转换结果再copy到EXCEL后求和后一对比就发现数据不对,我还是相信用Execl求和多一点。另外p_qry 过程不知什么意思, 执行出来结果不知是什么东西,好像没反应似的