Click here to monitor SSC
SQLServerCentral is supported by Red Gate Software Ltd.
 
Log in  ::  Register  ::  Not logged in
 
 
 
        
Home       Members    Calendar    Who's On


Add to briefcase 12345»»»

Pivot Table Help Needed Expand / Collapse
Author
Message
Posted Friday, October 19, 2007 11:59 AM
SSC-Enthusiastic

SSC-EnthusiasticSSC-EnthusiasticSSC-EnthusiasticSSC-EnthusiasticSSC-EnthusiasticSSC-EnthusiasticSSC-EnthusiasticSSC-Enthusiastic

Group: General Forum Members
Last Login: Tuesday, May 14, 2013 5:20 PM
Points: 137, Visits: 259
I have a result returned from a query that is the result of a join. I need to make the results rows to columns.
Here is my example:

Select OrderDate, OrderQty, ProductNo from view1

Result:
OrderDate --- OrderQty --- ProductNo

1/1/2007--------13-----------1000345
1/1/2007--------19-----------1000355
1/1/2007--------93-----------1000666
1/2/2007--------47-----------1000345
1/2/2007--------99-----------1000355
1/2/2007--------93-----------1000666

What I need from this data is this:

OrderDate---1000345---1000355---1000666

1/1/2007--------13-----------19-----------93
1/2/2007--------47-----------99-----------33
etc...

Thanks in Advance.
Post #412958
Posted Friday, October 19, 2007 12:18 PM
SSC-Addicted

SSC-AddictedSSC-AddictedSSC-AddictedSSC-AddictedSSC-AddictedSSC-AddictedSSC-AddictedSSC-Addicted

Group: General Forum Members
Last Login: Wednesday, May 01, 2013 8:10 AM
Points: 445, Visits: 840
Here is a Jeff MOden example I keep in my toolbox

Set NOCount On

---===== If the temp table to hold the results in exists, drop it
IF OBJECT_ID('TempDB..#Results') IS NOT NULL
DROP TABLE #Results

---===== Populate the temp table with results from your original query
select [field to be rows] as ciname,[filed to be columns] as attributename,sum([field to be aggregated]) as attributevalue
INTO #Results
from [your table/view]

IF @@RowCount = 0
Return


CREATE
INDEX [test] ON #Results ([AttributeName])


--===== Declare some local variables to hold some Dynamic SQL
DECLARE
@MySQL1 VARCHAR(8000)
DECLARE
@MySQL2 VARCHAR(8000)
DECLARE
@MySQL3 VARCHAR(8000)


--===== Build the SELECT clause
SET @MySQL1 = 'SELECT ciName,'


--===== Build the select LIST (do not try to reformat or you'll mess it up!)
SELECT @MySQL2 = ISNULL(@MySQL2 + ',','') + '
SUM(CASE WHEN AttributeName = ''' + AttributeName + '''
THEN AttributeValue ELSE NULL END) AS ' + '[' + AttributeName + ']'
FROM (SELECT DISTINCT TOP 100 PERCENT AttributeName AS AttributeName
FROM #Results
Order by AttributeName) d

--===== Build the FROM and GROUP BY clauses
SELECT @MySQL3 = CHAR(13) + 'FROM #Results GROUP BY ciName'


--===== Display the resulting SQL (you can take this piece out, just for demo)
--if @Debug = 1
PRINT @MySQL1+@MySQL2+@MySQL3

--===== Execute the Dynamic SQL
EXEC ( @MySQL1 +@MySQL2 +@MySQL3 )







Post #412961
Posted Friday, October 19, 2007 12:31 PM
SSC-Enthusiastic

SSC-EnthusiasticSSC-EnthusiasticSSC-EnthusiasticSSC-EnthusiasticSSC-EnthusiasticSSC-EnthusiasticSSC-EnthusiasticSSC-Enthusiastic

Group: General Forum Members
Last Login: Tuesday, May 14, 2013 5:20 PM
Points: 137, Visits: 259
Please allow me to add something else to this...

The columns will not change. This is not an example where the productno is changing. I have 3 Productno(s) and will never have any more, so the temp table can be statically built. The part I am stuck on is a query that will populate this table with the appropriate rows (inverted) as the number of rows will change (obviously).

Thanks for all of the quick responses so far.
Post #412965
Posted Friday, October 19, 2007 12:40 PM
SSC-Addicted

SSC-AddictedSSC-AddictedSSC-AddictedSSC-AddictedSSC-AddictedSSC-AddictedSSC-AddictedSSC-Addicted

Group: General Forum Members
Last Login: Wednesday, May 01, 2013 8:10 AM
Points: 445, Visits: 840
That is easier.

select orderdate,
sum(case when productno = 1000345 then orderqty else 0 end) as [1000345],
sum(case when productno = 1000355 then orderqty else 0 end) as [1000355],
sum(case when productno = 1000666 then orderqty else 0 end) as [1000666]
group by orderdate

This will sum all of the order quantites for a given day and product number.







Post #412969
Posted Friday, October 19, 2007 2:30 PM
SSC-Enthusiastic

SSC-EnthusiasticSSC-EnthusiasticSSC-EnthusiasticSSC-EnthusiasticSSC-EnthusiasticSSC-EnthusiasticSSC-EnthusiasticSSC-Enthusiastic

Group: General Forum Members
Last Login: Tuesday, May 14, 2013 5:20 PM
Points: 137, Visits: 259
We got it all worked out. Thanks to everyone who replied to this post.
Post #413000
Posted Saturday, October 20, 2007 12:01 AM


SSC-Dedicated

SSC-DedicatedSSC-DedicatedSSC-DedicatedSSC-DedicatedSSC-DedicatedSSC-DedicatedSSC-DedicatedSSC-DedicatedSSC-DedicatedSSC-DedicatedSSC-DedicatedSSC-DedicatedSSC-Dedicated

Group: General Forum Members
Last Login: Today @ 4:35 PM
Points: 32,930, Visits: 26,817
Here is a Jeff Moden example I keep in my toolbox

Heh... thank you kindly for the "plug" :D Got a present for ya, MrPoleCat...

 CREATE PROCEDURE dbo.AutoCrossTab
/**************************************************************************
Purpose:
-------
Given data in a 3 column external temp table, "auto-magically" create a
pivot report for that data.

Inputs:
-------
@pRowName:
Optional - Defaults to 'Row Name' and will appear down the left side
of the report in the first column.

@pTotals
Optional - Defaults to 0
0 = No totals
1 = Row totals displayed in last column on right
2 = Column totals displayed in last row at bottom
3 = Both sets of totals displayed

@pDebug
Optional - Defaults to 0
0 = Pivot report will be output
1 = SQL that creates the pivot report will be output

Outputs:
--------
Pivot report
Left Column - Created from RNam column of the existing #Results table.
Column Names - Totals will be named 'Total' for rows and columns.
- Left most column name defaults to 'Row Name' or may be
assigned by the @pRowName parameter.
- All other column names dervied from CNam column of the
existing #Results table.
Content - Sum aggragated CVal column from the existing #Results
table.

Revision History:
Rev 00 - Date Unk - Jeff Moden - Initial creation
Rev 01 - 10/20/2007 - Jeff Moden - Converted to stored procedure and
extra functionality added through
parameters explained above.
**************************************************************************/
--===== Declare the I/0 parameters
@pRowName VARCHAR(128) = 'Row Name',
@pTotals INTEGER = 0,
@pDebug INTEGER = 0
AS

--===== Setup the environment
SET NOCOUNT ON
SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED

--===== Declare some local variables to hold some Dynamic SQL
DECLARE @MySQL1 VARCHAR(8000) --SELECT and Row Name
DECLARE @MySQL2 VARCHAR(8000) --Select LIST
DECLARE @MySQL3 VARCHAR(8000) --Optional Row Totals
DECLARE @MySQL4 VARCHAR(8000) --FROM, GROUP BY, and optional column totals

--===== Build the SELECT clause
SET @MySQL1 =
CASE
WHEN @pTotals IN (2,3)
THEN 'SELECT CASE WHEN GROUPING(RNam) = 0 '
+ 'THEN CAST(RNam AS VARCHAR(128)) '
+ 'ELSE ''Total'' END [' + @pRowName + '],' + CHAR(13)
ELSE 'SELECT RNam[' + @pRowName + '],' + CHAR(13)
END

--===== Build the select LIST
SELECT @MySQL2 =
ISNULL(@MySQL2 + ','+CHAR(13),'') +
+ 'SUM(CASE WHEN CNam=''' + CNam + ''''
+ 'THEN CVal ELSE 0 END)' + '[' + CNam + ']'
FROM (--==== Derived table forces order of column names
SELECT DISTINCT TOP 100 PERCENT CNam AS CNam
FROM #Results
ORDER BY CNam) d

--===== If totals are turned on, calculate the row total
SELECT @MySQL3 =
CASE
WHEN @pTotals IN (1,3)
THEN CHAR(13) + ',SUM(CVal) AS Total'
ELSE ''
END

--===== Build the FROM and GROUP BY clauses
-- If the totals are turned on, calculate column totals
SELECT @MySQL4 =
CHAR(13) + 'FROM #Results GROUP BY RNam'
+ CASE
WHEN @pTotals IN (2,3)
THEN ' WITH ROLLUP'
ELSE ''
END

--===== If debug mode is on, just print the dynamic SQL...
-- Otherwise, execute the dynamic SQL
IF @pDebug = 1
PRINT @MySQL1+@MySQL2+@MySQL3+@MySql4
ELSE EXEC (@MySQL1+@MySQL2+@MySQL3+@MySql4)
GO

Note that the #Results table must exist prior to calling the proc above... here's the general format of the calling code...
--===== Setup the environment
SET NOCOUNT ON
SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED

--===== If the temp table to hold the #Results in exists, drop it
IF OBJECT_ID('TempDB..#Results') IS NOT NULL
DROP TABLE #Results

--===== Populate the temp table with #Results from your original query... for example...
SELECT [field to be rows] AS RNam, --<<< Column alias must be this
[field to be columns] AS CNam, --<<< Column alias must be this
SUM([field to be aggregated]) AS CVal --<<< Column alias must be this
INTO #Results --<<< Table name must be this!!!
FROM [your table/view]
GROUP BY [field to be rows], [field to be columns]

--===== Create an index for a little extra speed
CREATE CLUSTERED INDEX IDX_#Results_RNam ON #Results (RNam)

--===== Create either the Pivot table report or...
-- build the SQL that does so it can be "customized".
-- Parameters are for example... read the header of the proc for details
EXEC dbo.AutoCrossTab @pRowName = '2 Letter Account',
@pTotals = 3, --Print row and column totals
@pDebug = 0 --Display the report, not the dynamic SQL

I trimmed down the dynamic SQL as much as possible to handle 10 years of months named yyyy-mm and the totals.

Seriously, read the infomation in the header of the proc... I don't think folks are ever going to have to write code for a crosstab pivot ever again :P


--Jeff Moden
"RBAR is pronounced "ree-bar" and is a "Modenism" for "Row-By-Agonizing-Row".

First step towards the paradigm shift of writing Set Based code:
Stop thinking about what you want to do to a row... think, instead, of what you want to do to a column."

For better, quicker answers on T-SQL questions, click on the following...
http://www.sqlservercentral.com/articles/Best+Practices/61537/

For better answers on performance questions, click on the following...
http://www.sqlservercentral.com/articles/SQLServerCentral/66909/
Post #413058
Posted Monday, October 22, 2007 1:01 PM
SSC-Addicted

SSC-AddictedSSC-AddictedSSC-AddictedSSC-AddictedSSC-AddictedSSC-AddictedSSC-AddictedSSC-Addicted

Group: General Forum Members
Last Login: Wednesday, May 01, 2013 8:10 AM
Points: 445, Visits: 840
I will start with "VERY COOL".

One small fix I had to make to the set up is to switch the from and group by. I'd paste it here but it would be better if you edit your post for the next guy who uses it.



I tested my cursor version against this on a million rows ((your code with a few limitations on the data) with 365 dates for rows and 26 letters for columns, summing ints and yours is more than twice as fast. 20 seconds vs. 55 seconds. I think this is more due to the clustered index you are putting on the #Result table than it is on the cursor itself. I am going to see what better indexing on the original table does to narrow the gap.

One caveat is that my cursor version allows for more than one column in the rows and can handle the aggregate passed as a parameter.







Post #413544
Posted Monday, October 22, 2007 11:17 PM


SSC-Enthusiastic

SSC-EnthusiasticSSC-EnthusiasticSSC-EnthusiasticSSC-EnthusiasticSSC-EnthusiasticSSC-EnthusiasticSSC-EnthusiasticSSC-Enthusiastic

Group: General Forum Members
Last Login: Wednesday, March 31, 2010 6:02 PM
Points: 174, Visits: 2,075
Jeff,

If I was really mean I would make RAC open source :)

You could try to duplicate some functionality. Who knows you may come up with some good techniques. Then you will be in the ironic position of having to thank me for the motivation :)

best,
www.rac4sql.net
www.beyondsql.blogspot.com
Post #413674
Posted Monday, October 22, 2007 11:22 PM


SSC-Dedicated

SSC-DedicatedSSC-DedicatedSSC-DedicatedSSC-DedicatedSSC-DedicatedSSC-DedicatedSSC-DedicatedSSC-DedicatedSSC-DedicatedSSC-DedicatedSSC-DedicatedSSC-DedicatedSSC-Dedicated

Group: General Forum Members
Last Login: Today @ 4:35 PM
Points: 32,930, Visits: 26,817
If making RAC open source would stop your spamming, I'd be happy about that. :P And, your insults are a great way to drum up business

Just curious... how long does it take RAC to do the million row test to accomplish the same thing? I'm not talking about development time, I'm talking about execution time.


--Jeff Moden
"RBAR is pronounced "ree-bar" and is a "Modenism" for "Row-By-Agonizing-Row".

First step towards the paradigm shift of writing Set Based code:
Stop thinking about what you want to do to a row... think, instead, of what you want to do to a column."

For better, quicker answers on T-SQL questions, click on the following...
http://www.sqlservercentral.com/articles/Best+Practices/61537/

For better answers on performance questions, click on the following...
http://www.sqlservercentral.com/articles/SQLServerCentral/66909/
Post #413675
Posted Tuesday, October 23, 2007 12:08 AM


SSC-Dedicated

SSC-DedicatedSSC-DedicatedSSC-DedicatedSSC-DedicatedSSC-DedicatedSSC-DedicatedSSC-DedicatedSSC-DedicatedSSC-DedicatedSSC-DedicatedSSC-DedicatedSSC-DedicatedSSC-Dedicated

Group: General Forum Members
Last Login: Today @ 4:35 PM
Points: 32,930, Visits: 26,817
Fixed that... thanks for the observation... I always hate coverting working code into instructional code... I mess it up almost every time

--Jeff Moden
"RBAR is pronounced "ree-bar" and is a "Modenism" for "Row-By-Agonizing-Row".

First step towards the paradigm shift of writing Set Based code:
Stop thinking about what you want to do to a row... think, instead, of what you want to do to a column."

For better, quicker answers on T-SQL questions, click on the following...
http://www.sqlservercentral.com/articles/Best+Practices/61537/

For better answers on performance questions, click on the following...
http://www.sqlservercentral.com/articles/SQLServerCentral/66909/
Post #413681
« Prev Topic | Next Topic »

Add to briefcase 12345»»»

Permissions Expand / Collapse