August 18, 2008 at 10:59 pm
Comments posted to this topic are about the item Cross Tabs and Pivots, Part 1 – Converting Rows to Columns
--Jeff Moden
Change is inevitable... Change for the better is not.
August 19, 2008 at 1:41 am
[p]I hope I'm not mentioning anything that you are covering in subsequent articles, but when you need row and column totals, averages, or other aggregations, then suddenly the CUBE and ROLLUP operators start to become very useful. To take your example....[/p]
[font="Courier New"]
SELECT
COALESCE(CONVERT(CHAR(4),YEAR),'Sum'),
STR(SUM(CASE WHEN Quarter = 1 THEN Amount ELSE 0 END),5,1) AS [1st Qtr],
STR(SUM(CASE WHEN Quarter = 2 THEN Amount ELSE 0 END),5,1) AS [2nd Qtr],
STR(SUM(CASE WHEN Quarter = 3 THEN Amount ELSE 0 END),5,1) AS [3rd Qtr],
STR(SUM(CASE WHEN Quarter = 4 THEN Amount ELSE 0 END),5,1) AS [4th Qtr],
STR(SUM(Amount),5,1) AS Total
FROM #SomeTable1
GROUP BY YEAR WITH ROLLUP ORDER BY GROUPING(YEAR)
/*
1st Qtr 2nd Qtr 3rd Qtr 4th Qtr Total
---- ------- ------- ------- ------- -----
2006 1.1 1.2 1.3 1.4 5.0
2007 2.1 2.2 2.3 2.4 9.0
2008 1.5 0.0 2.3 1.9 5.7
Sum 4.7 3.4 5.9 5.7 19.7
*/
[/font]
[p] I love crosstabs and pivot-tables. Soothing, they are, like knitting.[/p]
Best wishes,
Phil Factor
August 19, 2008 at 3:55 am
That's interesting. I had my doubts as to how useful pivot might be. It's good to see it backed up by examples and statistics.
I'm looking forward to what you have to say about dynamic cross tabs. I recently had to do a cross tab for an electronic voting system using proportional representation where each election can have a different number of candidates. The only solution I could come up with in the time available works but is so complicated as to be ridiculous.
August 19, 2008 at 5:01 am
Jeff Moden (8/18/2008)
Comments posted to this topic are about the item
What a performance! Access SQL had the Pivot command from 1992, it's taken 13 years for SQL proper to catch up. About to convert an Access db to a SQL Express back-end. I imagine the X-tab queries will be a major nightmare.
pj
August 19, 2008 at 5:03 am
Phil Factor (8/19/2008)
[p]I hope I'm not mentioning anything that you are covering in subsequent articles, but when you need row and column totals, averages, or other aggregations, then suddenly the CUBE and ROLLUP operators start to become very useful. To take your example....[/p]
Actually, you did, Phil... I'm devestated... 😉
True enough... that will be in a subsequent article, but you've stolen no thunder. Thank you for the feedback ol' friend.
--Jeff Moden
Change is inevitable... Change for the better is not.
August 19, 2008 at 5:09 am
Peter Smith (8/19/2008)
Jeff Moden (8/18/2008)
Comments posted to this topic are about the itemWhat a performance! Access SQL had the Pivot command from 1992, it's taken 13 years for SQL proper to catch up. About to convert an Access db to a SQL Express back-end. I imagine the X-tab queries will be a major nightmare.
pj
I agree... thanks for the feedback, Peter. You'd think that if MS wanted to make it easier, they'd have come up with something a lot easier than Pivot syntax. What would be interesting would be to do a million row test on manual cross-tab vs the automatic cross-tab functionality in Access. If it's done right, the automatic cross-tab should should win by a significant margin.
--Jeff Moden
Change is inevitable... Change for the better is not.
August 19, 2008 at 5:19 am
Jeff, I've copied your code. Maybe it will reduce the bad language as the upscaling to SQL takes place. Thanks for the article.
August 19, 2008 at 5:24 am
gr8 article Jeff. Keep them coming.
"Keep Trying"
August 19, 2008 at 6:29 am
That was an amazing article. :w00t: Thanks so much, Jeff.
Paul DB
August 19, 2008 at 6:35 am
Hey Jeff, good article. It's funny I have answered several forum questions recently using a Case embedded in an aggregate. They weren't crosstabs exactly, but similar. So, after having answered these questions I decided to post it on my blog, hoping someone might stumble upon it on a search. I was even considering submitting an article to SSC on it, but you beat me to the punch. At least the info is out there and with much more performance testing done on it than I would have done. Looking forward to the rest of the series.
Jack Corbett
Consultant - Straight Path Solutions
Check out these links on how to get faster and more accurate answers:
Forum Etiquette: How to post data/code on a forum to get the best help
Need an Answer? Actually, No ... You Need a Question
August 19, 2008 at 7:42 am
Really nice to read, Jeff, and absolutely spot on.
I've had to do pivots in the last couple of weeks, with an unknown number of output (transposed) columns with unknown names, as in the following. It will be interesting to see your solution, you have a knack of coming up with "why the heck didn't I think of that?" solutions!
Cheers
ChrisM
SET NOCOUNT ON
CREATE TABLE #EDIInvoices (HospitalName VARCHAR(20), Purchaser VARCHAR(20), Sales money)
INSERT INTO #EDIInvoices (HospitalName, Purchaser, Sales)
SELECT 'Guy''s', 'BUPA', 10001 UNION ALL
SELECT 'Guy''s', 'Microsoft', 10002 UNION ALL
SELECT 'Guy''s', 'NIH', 10003 UNION ALL
SELECT 'Tommy''s', 'BUPA', 20001 UNION ALL
SELECT 'Tommy''s', 'Microsoft', 20002 UNION ALL
SELECT 'Tommy''s', 'NIH', 20003 UNION ALL
SELECT 'Tommy''s', 'Cornhill', 20004 UNION ALL
SELECT 'Raigmore', 'BUPA', 30001 UNION ALL
SELECT 'Raigmore', 'Microsoft', 30002 UNION ALL
SELECT 'Raigmore', 'NIH', 30003 UNION ALL
SELECT 'Raigmore', 'Cornhill', 30004 UNION ALL
SELECT 'Raigmore', 'HPA', 30005 UNION ALL
SELECT 'Raigmore', 'RaigmoreOnly', 30006 UNION ALL
SELECT 'Yorkhill', 'BUPA', 40001 UNION ALL
SELECT 'Yorkhill', 'Microsoft', 40002 UNION ALL
SELECT 'Yorkhill', 'Cornhill', 40004 UNION ALL
SELECT 'Yorkhill', 'HPA', 40005 UNION ALL
SELECT 'Yorkhill', 'YorkhillOnly', 40007
--SELECT * FROM #EDIInvoices -- Sanity check
-- PIVOT the results
DECLARE @SQLstr VARCHAR(5000)
SET @SQLstr = ''
SELECT @SQLstr = @SQLstr + CHAR(10) + ' MAX(CASE Purchaser WHEN ''' + Purchaser + ''' THEN Sales ELSE 0 END) AS [' + Purchaser + '], '
FROM (SELECT Purchaser FROM #EDIInvoices GROUP BY Purchaser) d
SET @SQLstr = 'SELECT HospitalName, ' + REVERSE(STUFF(REVERSE(@SQLstr),1,2,'')) + ' ' + CHAR(10) + 'INTO ##EDIInvoicesPivot FROM #EDIInvoices GROUP BY HospitalName'
PRINT @SQLstr -- sanity check
EXECUTE (@SQLstr)
SELECT * FROM ##EDIInvoicesPivot
DROP TABLE #EDIInvoices
DROP TABLE ##EDIInvoicesPivot
For fast, accurate and documented assistance in answering your questions, please read this article.
Understanding and using APPLY, (I) and (II) Paul White
Hidden RBAR: Triangular Joins / The "Numbers" or "Tally" Table: What it is and how it replaces a loop Jeff Moden
August 19, 2008 at 7:51 am
Check out this article on Dynamic Crosstabs by Jeff Smith:
http://weblogs.sqlteam.com/jeffs/archive/2005/05/02/4842.aspx
-smc
August 19, 2008 at 8:01 am
I am interested as to how or if we can pull a cross-tab or pivot dynamically. I have a query that can have an undetermined amount of comments associated to one job. In the query I need to show these comments in one line.
SET NOCOUNT ON
CREATE TABLE #BidComments (BidId int, Comment VARCHAR(varchar(max))
INSERT INTO #BidComments (BidId , Comment)
SELECT 1, 'This is comment 1 for bid 1' UNION ALL
SELECT 1, 'This is comment 2 for bid 1' UNION ALL
SELECT 1, 'This is comment 3 for bid 1' UNION ALL
SELECT 2, 'This is comment 1 for bid 2' UNION ALL
SELECT 2, 'This is the second comment for bid 2' UNION ALL
SELECT 2, 'Here we have the third comment for bid2' UNION ALL
SELECT 2, 'Comment 4' UNION ALL
SELECT 3, '1 comment on 3' UNION ALL
SELECT 3, 'comments for 3, the second' UNION ALL
SELECT 3, 'comment 3' UNION ALL
SELECT 3, 'Comment 4' UNION ALL
SELECT 3, 'Comment 5' UNION ALL
In the end I need to display it as
BidID Comment1 Comment2 Comment3
Any thoughts?
August 19, 2008 at 8:48 am
Congratulations on a well-written and informative article.
August 19, 2008 at 8:48 am
Great article Jeff. Keep 'em coming.
ATBCharles Kincaid
Viewing 15 posts - 1 through 15 (of 243 total)
You must be logged in to reply to this topic. Login to reply