Please start any new threads on our new
site at https://forums.sqlteam.com. We've got lots of great SQL Server
experts to answer whatever question you can come up with.
Author |
Topic |
zatlas1
Starting Member
3 Posts |
Posted - 2011-03-06 : 12:21:18
|
I've developed a (first) version of za_transform, to create MS-Access like cross-tabs in SQL Server. The user interface of my stored procedure (API) was kept compatible with the venerable (and genius) sp_transform. The result look like the result of using PIVOT in SQL Server and are NOT fully compatible with the results of sp_transform. I wrote this as a proof of concept and herein release it to the public for review, comments, suggestions, corrections and improvements.My version uses a temporary table since I could not find a way to use a table variable in a mix of static and dynamic SQL. It uses features that were not available in SQL Server 2k such as XML PATH FOR and PIVOT. Therefore it is not compatible with SQL Server 2k and will only work on SQL Server 200, 2008 and beyond./****** Object: StoredProcedure [dbo].[za_transform] Script Date: 03/03/2011 23:20:26 ******/SET ANSI_NULLS ONGOSET QUOTED_IDENTIFIER ONGO-- =============================================-- Author: <Ze'ev AStlas>-- Create date: <3/1/2011>-- Description: <implementation of MS Access Transform-like command>---- Version 1.0-- Published (temporarily) under LGPL 3.0-- Next versions may switch to another open source license---- Simpliistic implemetation-- Usage:-- EXEC @return_value = [dbo].[za_transform]-- @Aggregate_Function = aggregate function (e.g. N'sum'), [default sum]-- @Aggregate_Column = column to aggregate using the funcion,-- @TableOrView_Name = table name or select query. Must contain the pivot column,-- @Select_Column = row header columns, [PIVOT allows more then one]-- @Pivot_Column = the field to pivot on,-- @IN nvarchar = default NULL - Fixed values used to create column headings-- THIS OPTION IS NOT YET IMPLEMENTED,-- @DEBUG = 0/1 (currently default 1) print the select/pivot statement---- This implemetation use a temporary table #_ZAT_pivotNames that is dropped in the -- end of the run. -- This version implements partial and very simplistic error checking.-- Note that the user interface for this sproc was made to be compatible-- with the popular sp_transform. New parameters are added in the end of -- the parameter list, except of flags such as DEBUG. -- This sproc was designed to use new (2005, 2008, etc.) features in SQL-- server such as FOR XML PATH and PIVOT, but the autor is still full of-- owe for the achivement of sp_transform and what could be done with -- the primitive tools available in 2000.---- =============================================ALTER PROCEDURE [dbo].[za_transform] @Aggregate_Function nvarchar (2000), @Aggregate_Column nvarchar (2000), @TableOrView_Name nvarchar (2000), @Select_Column nvarchar (2000) = null, @Pivot_Column nvarchar (2000), @IN nvarchar(2000) = null, @DEBUG bit = 1ASBEGIN SET NOCOUNT ON;IF OBJECT_ID('tempdb..#_ZAT_pivotNames','u') IS NOT NULL drop table #_ZAT_pivotNames;declare @tableName nvarchar(2000);declare @PivotColumnName nvarchar(2000);declare @aggregate nvarchar(2000);declare @rowHeader nvarchar(2000); declare @inList nvarchar (2000); --< develop this ideadeclare @return int = 0; --< develop this idea-- Develop total option.declare @SQLSTR nvarchar (max);declare @i int;IF @Aggregate_Function NOT IN ('SUM', 'COUNT', 'MAX', 'MIN', 'AVG', 'STDEV', 'VAR', 'VARP', 'STDEVP') BEGIN RAISERROR ('Invalid aggregate function: %s', 0, 1, @Aggregate_Function) set @return = -1; goto droptabEND create table #_ZAT_pivotNames (pivotName sql_variant);set @tableName = @TableOrView_Nameset @PivotColumnName = @Pivot_Columnset @aggregate = @Aggregate_Function + '(' + @Aggregate_Column + ')'if @Select_Column is not null set @rowHeader = @Select_Column + ',' + @PivotColumnName + ',' + @Aggregate_Columnelse set @rowHeader = '*'if ltrim (@tableName) like 'select %'begin set @tableName = '(' + @tableName + ') a'endset @tableName = '(select ' + @rowHeader +' from ' + @tableName + ') b'set @tableName = '(select * from ' + @tableName + ')'set @SQLSTR = 'insert into #_ZAT_pivotNames ' + 'select distinct ' + @PivotColumnName + ' from ' + @tableName + ' a;'exec @i = sp_executesql @SQLSTRif @i <> 0begin RAISERROR ('Invalid return code from sp_executesql: %d5', 0, 1, @i) set @return = -1; goto droptabendselect @i = count (*) from #_ZAT_pivotNameswhere cast(pivotName as nvarchar(2000)) like '%\[%' escape '\'or cast(pivotName as nvarchar(2000)) like '%\]%' escape '\';-- I may use QUOTENAME with its limitations or replace all ] by ]]if coalesce(@i,0) <> 0BEGIN RAISERROR ('Invalid pivot column value: [ or ]', 0, 1) set @return = -1; goto droptabEND elsebegin set @SQLSTR = (SELECT '[' + cast (pivotName as nvarchar(2000)) + '],' FROM #_ZAT_pivotNames FOR xml PATH('')); set @SQLSTR = left (@SQLSTR, len(@SQLSTR) -1) set @SQLSTR = 'SELECT * from ' + @tableName + ' a PIVOT (' + @aggregate + ' FOR ' + @PivotColumnName + ' in (' + @SQLSTR + ')) as p;' if @DEBUG = 1 print @SQLSTR; exec @i = sp_executesql @SQLSTR if @i <> 0 begin RAISERROR ('Invalid return code from sp_executesql: %d5', 0, 2, @i) set @return = -1; goto droptab endenddroptab:drop table #_ZAT_pivotNames;return @return;ENDGO |
|
zatlas1
Starting Member
3 Posts |
Posted - 2011-03-08 : 17:20:48
|
Slightly improved version follows. This version will work properly in SQL Server 2005. It also checks for various null parameters.I have to make sure to prevent any SQL injection attacks!Also, I plan an option for 'total' row and to include 'in' clause like MS-Access transforem.Please come with suggestions./****** Object: StoredProcedure [dbo].[za_transform] Script Date: 03/03/2011 23:20:26 ******/SET ANSI_NULLS ONGOSET QUOTED_IDENTIFIER ONGO-- =============================================-- Author: <Ze'ev AStlas>-- Create date: <3/1/2011>-- Description: <implementation of MS Access Transform-like command>---- Version 1.01-- Published (temporarily) under LGPL 3.0-- Next versions may switch to another open source license---- Simpliistic implemetation-- Usage:-- EXEC @return_value = [dbo].[za_transform]-- @Aggregate_Function = aggregate function (e.g. N'sum'), [default sum]-- @Aggregate_Column = column to aggregate using the funcion,-- @TableOrView_Name = table name or select query. Must contain the pivot column,-- @Select_Column = row header columns, [PIVOT allows more then one]-- @Pivot_Column = the field to pivot on,-- @IN nvarchar = default NULL - Fixed values used to create column headings-- THIS OPTION IS NOT YET IMPLEMENTED,-- @DEBUG = 0/1 (currently default 1) print the select/pivot statement---- This implemetation use a temporary table #_ZAT_pivotNames that is dropped in the -- end of the run. -- This version implements partial and very simplistic error checking.-- Note that the user interface for this sproc was made to be compatible-- with the popular sp_transform. New parameters are added in the end of -- the parameter list, except of flags such as DEBUG. -- This sproc was designed to use new (2005, 2008, etc.) features in SQL-- server such as FOR XML PATH and PIVOT, but the autor is still full of-- owe for the achivement of sp_transform and what could be done with -- the primitive tools available in 2000.---- =============================================alter PROCEDURE [dbo].[za_transform] @Aggregate_Function nvarchar (2000),@Aggregate_Column nvarchar (2000),@TableOrView_Name nvarchar (2000),@Select_Column nvarchar (2000) = null,@Pivot_Column nvarchar (2000),@IN nvarchar(2000) = null,@DEBUG bit = 1ASBEGINSET NOCOUNT ON;IF OBJECT_ID('tempdb..#_ZAT_pivotNames','u') IS NOT NULLdrop table #_ZAT_pivotNames;declare @tableName nvarchar(2000);declare @PivotColumnName nvarchar(2000);declare @aggregate nvarchar(2000);declare @rowHeader nvarchar(2000); declare @inList nvarchar (2000); --< develop this ideadeclare @return int; --< develop this idea-- Develop total option.declare @SQLSTR nvarchar (max);declare @i int;set @return = 0;IF @Aggregate_Function is not nulland @Aggregate_Function NOT IN ('SUM', 'COUNT', 'MAX', 'MIN', 'AVG', 'STDEV', 'VAR', 'VARP', 'STDEVP') BEGIN RAISERROR ('Invalid aggregate function: %s', 0, 1, @Aggregate_Function) set @return = -1;goto droptabEND create table #_ZAT_pivotNames (pivotName sql_variant);set @tableName = @TableOrView_Nameset @PivotColumnName = @Pivot_Columnif @Aggregate_Function is nullbeginset @aggregate = 'SUM'endelsebeginset @aggregate = @Aggregate_Functionendif @Aggregate_Column is not nullbeginset @aggregate = @aggregate + '(' + @Aggregate_Column + ')'endelse beginRAISERROR ('Aggregate_Column cannot be null', 0, 1) set @return = -1;goto droptabendif @Pivot_Column is nullbeginRAISERROR ('Pivot_Column cannot be null', 0, 1) set @return = -1;goto droptabendif @Select_Column is not nullbeginset @rowHeader = @Select_Column + ',' + @PivotColumnName + ',' + @Aggregate_Columnendelse beginset @rowHeader = '*'endif ltrim (@tableName) like 'select %'beginset @tableName = '(' + @tableName + ') a'endset @tableName = '(select ' + @rowHeader +' from ' + @tableName + ') b'set @tableName = '(select * from ' + @tableName + ')'set @SQLSTR = 'insert into #_ZAT_pivotNames ' + 'select distinct ' + @PivotColumnName +' from ' + @tableName + ' a;'exec @i = sp_executesql @SQLSTRif @i <> 0begin RAISERROR ('Invalid return code from sp_executesql: %d5', 0, 1, @i) set @return = -1;goto droptabendselect @i = count (*) from #_ZAT_pivotNameswhere cast(pivotName as nvarchar(2000)) like '%\[%' escape '\'or cast(pivotName as nvarchar(2000)) like '%\]%' escape '\';-- I may use QUOTENAME with its limitations or replace all ] by ]]if coalesce(@i,0) <> 0BEGINRAISERROR ('Invalid pivot column value: [ or ]', 0, 1) set @return = -1;goto droptabEND elsebeginset @SQLSTR = (SELECT '[' + cast (pivotName as nvarchar(2000)) + '],'FROM #_ZAT_pivotNamesFOR xml PATH(''));set @SQLSTR = left (@SQLSTR, len(@SQLSTR) -1)if @tableName is null print 'tableName'if @aggregate is null print 'aggregate'if @PivotColumnName is null print 'PivotColumnName'if @SQLSTR is null print 'SQLSTR'set @SQLSTR = 'SELECT * from ' + @tableName +' a PIVOT (' + @aggregate + ' FOR ' + @PivotColumnName + ' in ('+ @SQLSTR +')) as p;'if @DEBUG = 1print '>>>===>' + @SQLSTR;exec @i = sp_executesql @SQLSTRif @i <> 0begin RAISERROR ('Invalid return code from sp_executesql: %d5', 0, 2, @i) set @return = -1;goto droptabendenddroptab:drop table #_ZAT_pivotNames;return @return;ENDGO |
|
|
Lumbago
Norsk Yak Master
3271 Posts |
Posted - 2011-03-09 : 04:11:03
|
Can you please add [ code ] tags around you sql code and also include usage examples with their corresponding output? I, and probably many like me, are not familiar with the Access like cross-tabs and/or sp_transform.- LumbagoMy blog-> http://thefirstsql.com/2011/02/07/regular-expressions-advanced-string-matching-and-new-split-function-sql-server-2008-r2/ |
|
|
zatlas1
Starting Member
3 Posts |
Posted - 2011-03-09 : 22:46:23
|
When preparing an answer, I've found a major deficiency. I will answer when I correct the thing. In essence, I cannot do a function as the pivot column.I will provide usage and brief explanation of cross-tab when I am done.ZA |
|
|
|
|
|
|
|