Technical Article

Creat a Pivot Table with several options

,

Create a pivot Table similiar to Microsoft Access Pivot Command, Specify if there should be totals at the bottom, right or both..
Uses a temporary table to hold the values..
Bad part is the SQL that is generated can have no more than
4000 Characters..
If not using any NVARCHAR characters, could make the sql up to 8000 Characters.

CREATE PROCEDURE proCrossTabMulti
(
@strSELECT NVARCHAR(750), -- 'SELECT A,B'
@strFROM NVARCHAR(750), -- 'FROM atabletest INNERJOIN atbl1 ON atbl1.int1 = atabletest.int1'
@strWHERE NVARCHAR(750), -- 'WHERE (((A <> ''A'') AND (A <>''B'')) OR (B = ''C''))'
@strConvertField NVARCHAR(50),  -- Field name to put at top strGroupI  
@strTotals NVARCHAR(6) = 'NONE',  -- Totals BOTTOM, RIGHT, BOTH, NONE, ALL
@strFields NVARCHAR(250), --Fields to Calc int1,int1,int2
@strFieldsAggregate NVARCHAR(250)  -- sum,avg,count  Aggregates for above @strFields number of arguments must match 
   )
AS
/************************************************************************************************
*** Developed by Chad Bowen 8/15/01
*** Executes a crosstab query that is similiar to Access PIVOT command
*** Converts on multiple fields
************************************************************************************************/
DECLARE @strReturn NVARCHAR(75)
DECLARE @strSQL NVARCHAR(4000)
DECLARE @intPosition1 INTEGER
DECLARE @intPosition2 INTEGER
DECLARE @strValu1 NVARCHAR(75)
DECLARE @strValu3 NVARCHAR(75)
DECLARE @intPosition3 INTEGER
DECLARE @intPosition4 INTEGER

SELECT name from sysobjects where name = 'TopTable'
IF @@ROWCOUNT > 0
 BEGIN
DROP TABLE TopTable
 END
CREATE TABLE TopTable
    ( strTop NVARCHAR(75))

SET @strSQL = 'INSERT INTO TopTable '
SET @strSQL = @strSQL + 'SELECT DISTINCT ' + @strConvertField --  CAST(' + @strConvertField + ' as NVARCHAR)'
SET @strSQL = @strSQL + ' ' +  @strFROM 
SET @strSQL = @strSQL + ' ' +  @strWHERE
PRINT @strSQL

--INSERT INTO @TopTable 
EXEC sp_executesql @strSQL

SET @strSQL = ''
SET @strSQL = @strSelect

DECLARE intCursor CURSOR FOR
SELECT * FROM topTable
OPEN intCursor
FETCH NEXT FROM intCursor INTO @strReturn
WHILE @@FETCH_STATUS = 0
 BEGIN
SET @intPosition1 = 1
SET @intPosition3 = 1
SET @intPosition2 = LEN(@strFields)
SET @intPosition4 = LEN(@strFieldsAggregate)
WHILE @intPosition2 <> 0
 BEGIN
  SET @intPosition2 = CHARINDEX(',',@strFields,@intPosition1)
SET @intPosition4 = CHARINDEX(',',@strFieldsAggregate,@intPosition3)
IF @intPosition2 = 0
 BEGIN
SET @strValu1 = SUBSTRING(@strFields,@intPosition1,LEN(@strFields))
 END
ELSE
 BEGIN
SET @strValu1 = SUBSTRING(@strFields,@intPosition1,@intPosition2 - @intPosition1)
IF @intPosition2 = LEN(@strFields)
 BEGIN
SET @intPosition2 = 0
 END
 END
IF @intPosition4 = 0
 BEGIN
SET @strValu3 = SUBSTRING(@strFieldsAggregate,@intPosition3,LEN(@strFieldsAggregate))
 END
ELSE
 BEGIN
SET @strValu3 = SUBSTRING(@strFieldsAggregate,@intPosition3,@intPosition4 - @intPosition3)
IF @intPosition3 = LEN(@strFieldsAggregate)
  BEGIN
SET @intPosition4 = 0
  END
 END
SET @intPosition3 = @intPosition4 + 1
SET @intPosition1 = @intPosition2 + 1
IF ((@intPosition2 = 0) AND (@intPosition4 <> 0)) OR ((@intPosition4 = 0) AND (@intPosition2<>0))
  BEGIN
PRINT 'CONFLICTING # of Arguments'
RETURN
  END
SET @strReturn = LTRIM(RTRIM(@strReturn))
  SET @strSQL = @strSQL + ',' + @strValu3 + '(CASE '
  SET @strSQL = @strSQL + @strConvertField  + ' WHEN ' + CHAR(39) + @strReturn + CHAR(39)
  SET @strSQL = @strSQL + ' THEN ' + @strValu1 + ' ELSE NULL END) AS ['
SET @strSQL = @strSQL + @strReturn + '-' + @strValu3 + '-' + @strValu1 + ']'
IF LEN(@strSQL) >=3999
 BEGIN
PRINT 'SQL Was to long limited to 4000 Characters'
 PRINT @strSQL
RETURN
 END
 END
FETCH NEXT FROM intCursor into @strReturn
 END
CLOSE intCursor
DEALLOCATE intCursor
IF @strTotals = 'RIGHT' OR @strTotals = 'BOTH' OR @strTotals = 'ALL'
 BEGIN
SET @intPosition1 = 1
SET @intPosition3 = 1
SET @intPosition2 = LEN(@strFields)
SET @intPosition4 = LEN(@strFieldsAggregate)
WHILE @intPosition2 <> 0

 BEGIN
  SET @intPosition2 = CHARINDEX(',',@strFields,@intPosition1)
SET @intPosition4 = CHARINDEX(',',@strFieldsAggregate,@intPosition3)
IF @intPosition2 = 0
 BEGIN
SET @strValu1 = SUBSTRING(@strFields,@intPosition1,LEN(@strFields))
 END
ELSE
 BEGIN
SET @strValu1 = SUBSTRING(@strFields,@intPosition1,@intPosition2 - @intPosition1)
IF @intPosition2 = LEN(@strFields)
 BEGIN
SET @intPosition2 = 0
 END
 END
IF @intPosition4 = 0
 BEGIN
SET @strValu3 = SUBSTRING(@strFieldsAggregate,@intPosition3,LEN(@strFieldsAggregate))
 END
ELSE
 BEGIN
SET @strValu3 = SUBSTRING(@strFieldsAggregate,@intPosition3,@intPosition4 - @intPosition3)
IF @intPosition3 = LEN(@strFieldsAggregate)
  BEGIN
SET @intPosition4 = 0
  END
 END
SET @intPosition3 = @intPosition4 + 1
SET @intPosition1 = @intPosition2 + 1
IF ((@intPosition2 = 0) AND (@intPosition4 <> 0)) OR ((@intPosition4 = 0) AND (@intPosition2<>0))
  BEGIN
PRINT 'CONFLICTING # of Arguments'
RETURN
  END
SET @strSQL = @strSQL + ',' + @strValu3 + '(' + @strValu1 + ') AS ['
SET @strSQL = @strSQL + @strValu3 + '-' + @strValu1 + ']'
IF LEN(@strSQL) >=3999
 BEGIN
PRINT 'SQL Was to long limited to 4000 Characters'
 PRINT @strSQL
RETURN
 END
 END
 END
IF @strTotals = 'BOTTOM' OR @strTotals = 'BOTH'  OR @strTotals = 'ALL'
 BEGIN
SET @strSQL = @strSQL + ',' + 'GROUPING('
IF CHARINDEX ( ',', @strSELECT,0) > 0
 BEGIN
SET @strSQL = @strSQL + SUBSTRING(@strSELECT,8,CHARINDEX ( ',', @strSELECT,0)-8) + ') ''grp'''
 END
ELSE
 BEGIN
SET @strSQL = @strSQL + SUBSTRING(@strSELECT,8,LEN(@strSELECT)) + ') ''grp'''
 END
 END
SET @strSQL = @strSQL + ' ' + @strFROM
SET @strSQL = @strSQL + ' ' + @strWHERE
SET @strSQL = @strSQL + ' GROUP BY ' + SUBSTRING(@strSELECT,8, LEN(@strSelect) - 7)
IF @strTotals = 'BOTTOM' OR @strTotals = 'BOTH'
 BEGIN
SET @strSQL = @strSQL + ' WITH ROLLUP'
 END
IF @strTotals = 'ALL'
 BEGIN
SET @strSQL = @strSQL + ' WITH CUBE'
 END
IF LEN(@strSQL) >=3999
 BEGIN
PRINT 'SQL Was to long limited to 4000 Characters'
 PRINT @strSQL
RETURN
 END

PRINT @strSQL 

SELECT * FROM TopTable
PRINT LEN(@strSQL)
EXEC sp_executesql @strSQL

RETURN


GO

Rate

You rated this post out of 5. Change rating

Share

Share

Rate

You rated this post out of 5. Change rating