标签:
在做报表开发时,遇到这样的需求:
当前要开发的报表A,其数据来源于另一张已经开发好的基础报表B。
(1)由于统计维度不同,从基础报表B获取的数据需要做进一步的处理。
(2)当基础报表B的取数逻辑发生变更时,报表A的取数逻辑也要做相应的变更,保持取数逻辑的一致。
经分析,由于报表A和报表B均为存储过程返回的结果集,实为调用和被调用的关系。
于是问题的关键点转化为:存储过程A该如何调用存储过程B,才能灵活的使用存储过程B返回的结果集。
以下案例中隐去真实的业务场景(甄士隐去,贾雨村言)
首先,我们对存储过程B,做个微整形,效果如下:
1 CREATE PROCEDURE usp_MyProc_B 2 ( 3 --隐去其他参数,在末尾新增可为空的输入参数@TmpTB 4 @TmpTB AS VARCHAR(MAX)=‘‘ --全局临时表表名 5 ) 6 AS 7 /************************************************************************* 8 Author:huangcx 9 DATE : 2016-01-18 10 ------------------------------------------------------------------------- 11 DECLARE @TmpTB VARCHAR(MAX) 12 SET @TmpTB=‘##tmpdata‘ + REPLACE(CONVERT(VARCHAR(100), NEWID()),‘-‘,‘_‘) 13 EXEC usp_MyProc_B @TmpTB 14 *************************************************************************/ 15 BEGIN 16 17 DECLARE @sql VARCHAR(MAX) 18 IF @TmpTB<>‘‘ AND EXISTS(select 1 from tempdb..sysobjects where id=object_id(‘tempdb..‘+@TmpTB) and type=‘U‘) 19 BEGIN 20 SET @sql = ‘DROP TABLE ‘ + @TmpTB 21 EXEC(@sql) 22 END 23 24 --处理数据,生成结果集 25 --此处隐去真实的业务场景,代以一个简单的语句 26 SELECT * INTO #tmp FROM p_Project 27 --真事隐去,假语村言 28 29 --结果集存入全局表,不返回结果集 30 IF @TmpTB<>‘‘ 31 BEGIN 32 SET @sql = ‘SELECT * INTO ‘+ @TmpTB +‘ FROM #tmp‘ 33 EXEC(@sql) 34 END 35 36 ELSE 37 --返回结果集 38 BEGIN 39 SELECT * FROM #tmp 40 END 41 42 --删除临时表 43 DROP TABLE #tmp 44 END 45 46 GO
其次,我们获取存储过程B的返回结果集时,需要创建一张表结构与结果集一样的临时表来承载这个结果集。
考虑到后期,存储过程B可能会有所变更,结果集的字段不会是一成不变的,因此需要设法动态的获取结果集的表结构定义。
由于本人功力有限,还请高手路过时,不吝赐教,授予神功秘籍。本人能想到实现方式如下:
1 CREATE PROCEDURE usp_GetTableDefine 2 ( 3 @TableName AS VARCHAR(MAX), 4 @DefineStr AS VARCHAR(MAX)=‘‘ OUTPUT 5 ) 6 AS 7 /************************************************************ 8 Author:huangcx 9 DATE : 2016-01-18 10 ------------------------------------------------------------ 11 DECLARE @DefineStr VARCHAR(4000) 12 EXEC usp_GetTableDefine ‘p_Project‘,@DefineStr output 13 SELECT @DefineStr 14 ************************************************************/ 15 BEGIN 16 17 DECLARE @temp TABLE 18 ( 19 id INT IDENTITY(1, 1), 20 colname sysname, 21 typename sysname, 22 pre smallint, 23 scale int 24 ) 25 DECLARE @id int 26 DECLARE @colname varchar(50) 27 DECLARE @typename varchar(50) 28 DECLARE @pre varchar(50) 29 DECLARE @scale varchar(50) 30 DECLARE @str varchar(max) 31 32 --普通表 33 --region 34 IF EXISTS(select 1 from sysobjects where id=object_id(@TableName) and type=‘U‘) 35 BEGIN 36 --print ‘普通表‘ 37 INSERT INTO @temp(colname,typename,pre,scale) 38 SELECT 39 col.name, 40 typ.name, 41 col.prec, 42 col.scale 43 FROM sysobjects obj 44 left join syscolumns col on col.id=obj.id 45 left join systypes typ on typ.xtype=col.xtype 46 WHERE obj.type=‘u‘ 47 and obj.id=OBJECT_ID(@TableName) 48 ORDER BY col.colorder 49 END 50 --endregion 51 52 --临时表 53 --region 54 IF EXISTS(select 1 from tempdb..sysobjects where id=object_id(‘tempdb..‘+@TableName) and type=‘U‘) 55 BEGIN 56 --print ‘临时表‘ 57 INSERT INTO @temp(colname,typename,pre,scale) 58 SELECT 59 col.name, 60 typ.name, 61 col.prec, 62 col.scale 63 FROM tempdb..sysobjects obj 64 left join tempdb..syscolumns col on col.id=obj.id 65 left join tempdb..systypes typ on typ.xtype=col.xtype 66 WHERE obj.type=‘u‘ 67 and obj.id=OBJECT_ID(‘tempdb..‘+@TableName) 68 ORDER BY col.colorder 69 END 70 --endregion 71 72 --region 取出所有字段定义 73 SET @DefineStr=‘‘ 74 WHILE EXISTS (SELECT [id] FROM @temp) 75 BEGIN 76 77 SET ROWCOUNT 1 78 79 SELECT 80 @id=id, 81 @colname=colname, 82 @typename=typename, 83 @pre=pre, 84 @scale=scale 85 FROM @temp 86 87 SET ROWCOUNT 0 88 89 DELETE FROM @temp WHERE id=@id 90 91 --PRINT ‘ColName:‘ + @colname 92 --首行 93 IF @id = 1 94 BEGIN 95 --1.不指定长度和精度 96 IF @typename IN (‘sysname‘,‘bit‘,‘timestamp‘,‘bigint‘,‘tinyint‘,‘smalldatetime‘,‘money‘,‘smallint‘,‘uniqueidentifier‘,‘text‘,‘ntext‘,‘image‘,‘geography‘,‘geometry‘,‘hierarchyid‘,‘sql_variant‘,‘xml‘,‘date‘,‘datetime‘,‘datetime2‘,‘datetimeoffset‘,‘int‘,‘real‘,‘smallmoney‘,‘time‘) 97 BEGIN 98 SET @DefineStr=@DefineStr+‘[‘+@colname+‘]‘ + ‘ ‘ + @typename 99 END 100 --2.只指定长度,不指定精度 101 IF @typename IN (‘nvarchar‘,‘char‘,‘varchar‘,‘binary‘,‘float‘,‘nchar‘,‘varbinary‘) 102 BEGIN 103 SET @DefineStr=@DefineStr+‘[‘+@colname+‘]‘ + ‘ ‘ + @typename + ‘(‘+ @pre +‘)‘ 104 END 105 --3.同时指定长度和精度 106 IF @typename IN (‘numeric‘,‘decimal‘) 107 BEGIN 108 SET @DefineStr=@DefineStr+‘[‘+@colname+‘]‘ + ‘ ‘ + @typename + ‘(‘+ @pre + ‘,‘ + @scale + ‘)‘ 109 END 110 END 111 --非首行 112 ELSE 113 BEGIN 114 --1.不指定长度和精度 115 IF @typename IN (‘sysname‘,‘bit‘,‘timestamp‘,‘bigint‘,‘tinyint‘,‘smalldatetime‘,‘money‘,‘smallint‘,‘uniqueidentifier‘,‘text‘,‘ntext‘,‘image‘,‘geography‘,‘geometry‘,‘hierarchyid‘,‘sql_variant‘,‘xml‘,‘date‘,‘datetime‘,‘datetime2‘,‘datetimeoffset‘,‘int‘,‘real‘,‘smallmoney‘,‘time‘) 116 BEGIN 117 SET @DefineStr=@DefineStr + ‘,‘ + ‘[‘+@colname+‘]‘ + ‘ ‘ + @typename 118 END 119 --2.只指定长度,不指定精度 120 IF @typename IN (‘nvarchar‘,‘char‘,‘varchar‘,‘binary‘,‘float‘,‘nchar‘,‘varbinary‘) 121 BEGIN 122 SET @DefineStr=@DefineStr + ‘,‘ + ‘[‘+@colname+‘]‘ + ‘ ‘ + @typename + ‘(‘+ @pre +‘)‘ 123 END 124 --3.同时指定长度和精度 125 IF @typename IN (‘numeric‘,‘decimal‘) 126 BEGIN 127 SET @DefineStr=@DefineStr + ‘,‘ + ‘[‘+@colname+‘]‘ + ‘ ‘ + @typename + ‘(‘+ @pre + ‘,‘ + @scale + ‘)‘ 128 END 129 END 130 --print @DefineStr 131 END 132 --endregion 133 --select @DefineStr 134 END 135 136 GO
最后,就是存储过程B的实现了。
依旧隐去真实的业务场景,阉割后的存储过程B实现如下:
1 DECLARE @TmpTB VARCHAR(MAX) --全局临时表 2 DECLARE @TableStr VARCHAR(MAX) --添加字段定义 3 DECLARE @DataStr VARCHAR(MAX) --插入数据行 4 DECLARE @DefineStr VARCHAR(MAX) --表字段定义 5 6 --设置全局临时表表名 7 SET @TmpTB=‘##tmpdata‘ + REPLACE(CONVERT(VARCHAR(100), NEWID()),‘-‘,‘_‘) 8 9 --调用存储过程,结果集存入全局临时表 10 EXEC usp_MyProc_01 @TmpTB 11 12 --输出表字段定义 13 EXEC usp_GetTableDefine @TmpTB,@DefineStr output 14 15 16 /* 17 这里先创建临时表,再添加表字段。 18 这是由于用EXEC()创建的临时表,也只能在EXEC()中才能使用。 19 */ 20 --创建临时表 21 CREATE TABLE #tmp(id int) 22 SET @TableStr = ‘ALTER TABLE #tmp ADD ‘+@DefineStr+‘ ‘ 23 --PRINT @TableStr 24 EXEC(@TableStr) 25 EXEC(‘ALTER TABLE #tmp DROP COLUMN id‘) 26 27 --数据插入临时表 28 SET @DataStr = ‘INSERT INTO #tmp SELECT * FROM ‘ + @TmpTB 29 PRINT @DataStr 30 EXEC(@DataStr) 31 32 --删除全局表 33 EXEC(‘DROP TABLE ‘+@TmpTB) 34 35 /* 36 这样就可以愉快地使用存储过程返回的结果集了 37 此处省略对结果集的实际处理过程 38 */ 39 --使用临时表数据 40 SELECT * FROM #tmp 41 42 43 --删除临时表数据 44 DROP TABLE #tmp
标签:
原文地址:http://www.cnblogs.com/newhcx/p/5139924.html