Oracle FAQ Your Portal to the Oracle Knowledge Grid
HOME | ASK QUESTION | ADD INFO | SEARCH | E-MAIL US
 

Home -> Community -> Usenet -> c.d.o.misc -> Re: reverse pivoting

Re: reverse pivoting

From: Billy Verreynne <vslabs_at_onwe.co.za>
Date: Tue, 12 Mar 2002 06:12:59 GMT
Message-ID: <3c8d97ac.61762883@news.saix.net>


"Kenny Yu" <kyu_at_biodiscovery.com> wrote:

>Is there systematic approaches in data warehousing to do the following
>converting table Pivot (customer, product, amount) -- many rows per
>customer into table RPivot (customer, prod1Amt, prod2Amt, ... prodnAmt)
> -- one row per customer

Yes.

>I am interested in a pure SQL way.

What is pure SQL?

And why is this that I have answered this same question a few times a year in this newsgroup since '97... ;-)

Here's a copy and paste of an old posting (dug up in groups.google) on the topic I made:

--
The trick is to create a pivot table, and join the data set with that.
The result set will then be pivoted or cross-tabbed, i.e. you make
columns into rows and rows into columns.

This is best explained with a little example.

YEARLY_RESULTS:
Year Quarter Value
---- ------- -----
94   1       100
94   2       150
94   3       170
94   4       200
95   1       190
95   2       210
95   3       205
95   4       215

OK, you want the data of the above table to be displayed (via a SQL
SELECT statement) as follows:

Year Q1  Q2  Q3  Q4
---- --- --- --- ---
94   100 150 170 200
95   190 210 205 215


How to do it? First you need to create (what I call) a pivot table. We
want to pivot the QUARTER column and for a quarter  have 4 distinct
values. So we create the following table:

PIVOT_TABLE:
Quarter Q1  Q2  Q3  Q4
------- --  --  --  --
1       1   0   0   0
2       0   1   0   0
3       0   0   1   0
4       0   0   0   1

For Quarter One, only Q1 is "valid" and the others are "invalid". Thus
we mark the Q1 column for Quarter 1 with a one and the other columns
with zeros. Ditto for the other columns (reminiscent of bitmasking).

OK, now we join our data set with the pivot table.
SELECT
  yearly_results.year,
  SUM( yearly_results.value * pivot_table.q1) "Q1",
  SUM( yearly_results.value * pivot_table.q2) "Q2",
  SUM( yearly_results.value * pivot_table.q3) "Q3",
  SUM( yearly_results.value * pivot_table.q4) "Q4"
FROM yearly_results,
     pivot_table
WHERE yearly_results.quarter = pivot_table.quarter
GROUP BY
  yearly_results.year


The concept here is that we create 4 brand new columns - one for every
quarter. Then we sum the values from the yearly results table for each
of these 4 columns. However, we do not want to add quarter 1's value
into the wrong columns. Enter the pivot table - it causes quarter 1's
value to be multiplied with zero for any other quarter except quarter
1.
--

The above is the "purest" SQL way - but it needs the creation of an
additional table.

There are other methods too. 

Oracle supports the DECODE statement (which gives you IF-THEN-ELSE
capability in the SELECT statement). This statement can be used in
place of the pivot table.
SELECT
  year,
  SUM( DECODE( quarter, 1, value, 0) ) "Q1",
  SUM( DECODE( quarter, 2, value, 0) ) "Q2",
  SUM( DECODE( quarter, 3, value, 0) ) "Q3",
  SUM( DECODE( quarter, 4, value, 0) ) "Q4"
FROM yearly_results
GROUP BY year

This is nice and clean, however is not "standard SQL" (whatever that
may be).

You can do multiple cartesian joins on the the same table. Using the
above example:
SELECT
  q1.year,
  SUM( q1.value ) "Q1",
  SUM( q2.value ) "Q2",
  SUM( q3.value ) "Q3",
  SUM( q4.value ) "Q4",
FROM yearly_results q1,
     yearly_results q2,
     yearly_results q3,
     yearly_results q4
WHERE q1.quarter = 1
AND   q2.quarter = 2
AND   q3.quarter = 3
AND   q4.quarter = 4
AND   q1.year = q2.year
AND   q1.year = q3.year
AND   q1.year = q4.year
GROUP BY q1.year

Damn, don't you just love SQL! :-)

I have yet to find a query that can not be done in SQL.. 
--
Billy
Received on Tue Mar 12 2002 - 00:12:59 CST

Original text of this message

HOME | ASK QUESTION | ADD INFO | SEARCH | E-MAIL US