水如烟

                 顺其自然,水到渠成 LzmTW

文或代码皆是面向初学者.我是爱好者,也是初学者.那些"文章",只按自己理解写,我是不知术语名词的.所以只供参考,也仅供参考.

posts - 94, comments - 809, trackbacks - 1, articles - 0

原作者:John Papa, Matthew Shepker  1999
整理: 水如烟

示例:

Use pubs 
GO 
exec prCrosstab 'stor_id','ord_date','qty','sales',1,5 


结果:
 

RowHead

Year_1992

Year_1993

Year_1994

6380

0

0

8

7066

0

50

75

7067

80

0

10

7131

0

85

45

7896

0

60

0

8042

0

55

25


以下为生成脚本:

if exists (select * from dbo.sysobjects where id = object_id(N'[dbo].[prCrosstab]'and OBJECTPROPERTY(id, N'IsProcedure'= 1
drop procedure [dbo].[prCrosstab] 
GO 
 
SET QUOTED_IDENTIFIER ON 
GO 
SET ANSI_NULLS ON 
GO 
 
/* 
    功能:交叉制表 
    参数                描述 
    @chrRowHead        表示列,在交叉制表的结果中作为第一出现 
    @chrColHead        表示列,在交叉制表的结果中该列中的数据被变换为新列名称 
    @chrValue            表示列,在该列中执行聚合函数 
    @chrSource        源表或视图 
    @inyType            1-求和,2-平均值,3-最小值,4-最大值,5-计数 
    @inyGrouping        1-工作日,2-年内的周数,3-月份,4-季度,5-年份 
     
    Author:John Papa Matthew Shepker 
    整理: 水如烟(http://blog.csdn.net/lzmtw) 
    日期:5-1-2005 
*/
 
 
 
CREATE PROCEDURE prCrosstab 
    
@chrRowHead        char(30), 
    
@chrColHead        char(30), 
    
@chrValue            char(30), 
    
@chrSource        char(30), 
    
@inyType            tinyint=1
    
@inyGrouping        tinyint=0 
AS 
 
/* Variables for the procedure */ 
DECLARE 
    
@chvRow            varchar(255), 
    
@chvCol            varchar(255), 
    
@chvVal            varchar(255), 
    
@chvType            varchar(10), 
    
@chvRowType        varchar(10), 
    
@chvColType        varchar(255), 
    
@chvTemp            varchar(255), 
    
@chvColTemp        varchar(255), 
    
@chvRowTemp        varchar(255), 
    
@intType            int
    
@intRowType        int
    
@intColType        int
    
@chvExec            varchar(255), 
    
@chvGroup            varchar(255), 
    
@fltTemp            float
    
@dtmTemp            datetime
    
@insR            smallint
    
@intColumn        int
    
@intReturn        int
    
@intTemp            int
    
@intColNameLen    int
    
@intMaxRowHead    int 
     
    
SET NOCOUNT ON 
     
    
/* Check if source exists */ 
     
    
IF NOT EXISTS 
        (
SELECT * 
        
FROM sysobjects 
        
WHERE name = @chrSource 
        
AND type IN ('v','u')) 
    
BEGIN 
        
RAISERROR 51001 'Source does not exists.' 
        
RETURN -1 
    
END 
     
    
/* Check for column existence */ 
     
    
IF NOT EXISTS 
        (
SELECT sc.name 
        
FROM syscolumns sc 
            
JOIN sysobjects so ON sc.id = so.id 
        
WHERE so.name = @chrSource 
        
AND sc.name = @chrColHead
    
BEGIN 
        
RAISERROR 51002 'Invalid @chrColHead name.' 
        
RETURN -1 
    
END 
 
    
IF NOT EXISTS 
        (
SELECT sc.name 
        
FROM syscolumns sc 
            
JOIN sysobjects so ON sc.id = so.id 
        
WHERE so.name = @chrSource 
        
AND sc.name = @chrRowHead
    
BEGIN 
        
RAISERROR 51002 'Invalid @chrRowHead name.' 
        
RETURN -1 
    
END 
     
    
IF NOT EXISTS 
        (
SELECT sc.name 
        
FROM syscolumns sc 
            
JOIN sysobjects so ON sc.id = so.id 
        
WHERE so.name = @chrSource 
        
AND sc.name = @chrValue
    
BEGIN 
        
RAISERROR 51002 'Invalid @chrValue name.' 
        
RETURN -1 
    
END     
     
    
/* Verify type is valid (1(sum),2(avg),etc*/ 
     
    
IF @inyType < 1 OR @inyType > 5 
    
BEGIN 
        
RAISERROR 51000 'Invalid crosstab type.' 
        
RETURN -1 
    
END 
     
    
/* Create typestr to hold aggregate name */ 
     
    
SELECT @chvType= 
        
CASE @inyType 
        
WHEN 1 THEN 'SUM' 
        
WHEN 2 THEN 'AVG' 
        
WHEN 3 THEN 'MAX' 
        
WHEN 4 THEN 'MIN' 
        
WHEN 5 THEN 'COUNT' 
        
ELSE 'SUM' 
        
END 
         
    
/* Getstandard data type of @chrValue column */ 
     
    
SELECT @chvTemp = t2.name 
    
FROM sysobjects o 
        
JOIN syscolumns c ON o.id = c.id 
        
JOIN systypes t1 ON t1.usertype = c.usertype 
        
JOIN systypes t2 ON t1.type = t2.type 
    
WHERE t2.usertype < 100 
    
AND t2.usertype <> 18 
    
AND t2.usertype <> 80 
    
AND o.type IN ('u','v'
    
AND o.name = @chrSource 
    
AND c.name = @chrValue 
     
    
/* Categorize types for aggregate check */ 
     
    
SELECT @intTemp = 
        
CASE 
        
WHEN @chvTemp IN ('int','smallint','tinyint','float','real'
            
'decimal','numeric','monery','smallmoney')    THEN 1 
        
WHEN @chvTemp IN ('datetime','smalldatetime')    THEN 3 
        
WHEN @chvTemp IN ('bit','char','varchar')        THEN 5 
        
ELSE 100 
        
END 
         
    
/* validate existing data type is consistent with selected aggregate */ 
     
    
IF @inyType < @intTemp 
    
BEGIN 
        
RAISERROR 51020 'Crosstab type not valid with @chrValue definition.' 
        
RETURN -1 
    
END 
     
    
/* Hold the  data type for future use */ 
     
    
SELECT @chvColType = RTRIM
        
CASE @inyType 
        
WHEN 5 THEN 'int' 
        
ELSE CASE 
            
WHEN @chvTemp IN ('bit','char','varchar')    THEN 'int' 
            
WHEN @chvTemp IN ('decimal','numeric')        THEN 'float' 
            
ELSE @chvTemp 
            
END 
        
END
         
    
/* Verify grouping is valid for colhead */ 
     
    
IF @inyGrouping < 0 OR @inyGrouping > 5 
    
BEGIN 
        
RAISERROR 51010 'Invalid crosstab grouping.' 
        
RETURN -1 
    
END 
     
    
/* Getstandard data type of @chrColHead column */ 
     
     
SELECT @chvTemp = t2.name 
    
FROM sysobjects o 
        
JOIN syscolumns c ON o.id = c.id 
        
JOIN systypes t1 ON t1.usertype = c.usertype 
        
JOIN systypes t2 ON t1.type = t2.type 
    
WHERE t2.usertype < 100 
    
AND t2.usertype <> 18 
    
AND t2.usertype <> 80 
    
AND o.type IN ('u','v'
    
AND o.name = @chrSource 
    
AND c.name = @chrColHead 
     
    
IF UPPER(@chvTempNOT IN ('CHAR','VARCHAR'
        
SELECT @intColtype = 1 
    
ELSE 
        
SELECT @intColtype = 0 
         
    
/* Get standard data type of @chvRowHead */ 
     
    
SELECT @chvRowType = t2.name 
    
FROM sysobjects o 
        
JOIN syscolumns c ON o.id = c.id 
        
JOIN systypes t1 ON t1.usertype = c.usertype 
        
JOIN systypes t2 ON t1.type = t2.type 
    
WHERE t2.usertype < 100 
    
AND t2.usertype <> 18 
    
AND t2.usertype <> 80 
    
AND o.type IN ('u','v'
    
AND o.name = @chrSource 
    
AND c.name = @chrRowHead 
     
    
IF UPPER(@chvRowTypeNOT IN ('CHAR','VARCHAR'
        
SELECT @intRowtype = 1 
    
ELSE 
        
SELECT @intRowtype = 0 
         
    
/* Categorize types for grouping check */ 
     
    
SELECT @intTemp = 
        
CASE 
        
WHEN @chvTemp IN ('int','smallint','tinyint','float','real'
            
'decimal','numeric','monery','smallmoney')    THEN 1 
        
WHEN @chvTemp IN ('datetime','smalldatetime')    THEN 3 
        
WHEN @chvTemp IN ('bit','char','varchar')        THEN 5 
        
ELSE 100 
        
END 
         
    
/* Validate existing data type is consistant with selected grouping */ 
     
    
IF (@intTemp = 5 AND @inyGrouping > 0OR (@intTemp = 1 AND @inyGrouping > 0
        
OR (@intTemp =3 AND @inyGrouping =0
    
BEGIN 
        
RAISERROR 51030 'Crosstab grouping not valid with @chvColHead definition.' 
        
RETURN -1 
    
END 
     
    
/* Check for permission on source */ 
     
    
IF user_id() <> 1 
    
BEGIN 
        
IF    (SELECT COUNT(DISTINCT c.name) 
            
FROM syscolumns c,sysobjects o,sysprotects p, 
                sysusers u,master..spt_values v 
            
WHERE c.name IN (@chrColHead,@chrRowHead,@chrValue
            
AND c.id = o.id 
            
AND p.id = c.id 
            
AND c.colid = v.number 
            
AND v.type = 'p' 
            
AND o.id = object_id(@chrSource
            
AND (u.uid = user_id() OR u.uid IN 
                (
SELECT u1.uid 
                
FROM sysusers u1 
                
WHERE u1.gid = u1.uid 
                
AND u1.gid IN 
                    (
SELECT u2.gid 
                    
FROM sysusers u2 
                    
WHERE u2.uid = user_id() 
                    
OR u2.uid = user_id('public')))) 
            
AND p.uid = u.uid 
            
AND p.action = 193 
            
AND p.protecttype = 205 
            
AND columns IS NOT NULL 
    &nb