--行列互换例子:
--交叉表处理的通用存储过程
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
--交叉表处理的通用存储过程
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
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
@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