Skip to Main Content
  • Questions
  • Converting Vertical Rows Into Horizontal Rows

Breadcrumb

Question and Answer

Tom Kyte

Thanks for the question, Hariharan.

Asked: September 07, 2009 - 2:40 am UTC

Last updated: September 07, 2009 - 6:51 am UTC

Version: 10.2

Viewed 10K+ times! This question is

You Asked

Hi Tom,

Good Day.

I have an issue, which requires your expert suggestions and comments. In my company, the developers have created a table which is of the following format:

Customer Name, Identifier-1, Identifier-2 (other columns are also there in the table, but these 3 columns are the most vital ones).

Now, the data for these columns would be:

Martin, ChequeNo=929020, Value=2000
Martin, HouseNo=27, State='TamilNadu'
Martin, BankName='Bank of Baroda', Branch='T Nagar'
Luther, ChequeNo=922320, Value=2400
Luther, BankName='UBS', Branch='Zurich'
Shankar, ChequeNo=929590, Value=1200 .......

Please note that the number of rows varies for every customer. Some customer may have 5 rows and some may have 1

Now, they wanted to display this into horizontal as follows:

Martin, ChequeNo=929020, Value=2000, HouseNo=27, State='TamilNadu',BankName='Bank of Baroda', Branch='T Nagar'
Luther, ChequeNo=922320, Value=2400, BankName='UBS', Branch='Zurich'
Shankar, ChequeNo=929590, Value=1200

In order to do this, they have dynamically created inner joins to retrieve records. For example, If they wanted to display 'Martin' details they have 3 joins and for 'Luther' 2 joins. Another issue is, they are joining this table with 4 other tables where the number of rows runs in millions.

Now, my question:

The DBA suggested to denormalize, which I said No. Instead, I suggested them to use a view, which should dynamically converts these data into horizontal and keep it ready so that whenever they fetch, instead of fetching from the table they can fetch from this view. Even though there will be a small performance issue, this would be better than dynamically joining with the tables.

Please advise me if the solution suggested by me is feasible and if not, please provide me with an optimal solution.

Thanks a lot

Hari

and Tom said...

Your "developers" should be sent back to school. I've seen bad ideas before - but this is taking two or three of them and combining them for the "super bad idea to beat your bad idea"

Your developers stink, just my opinion.


... In order to do this, they have dynamically created inner joins to retrieve records. ...

Ok, now I *really* hate them, they more than stink, they - well, use your imagination.

I'll bet they complain "the database is slow" too.

... The DBA suggested to denormalize, ...

how can you denormalize this ?!?!?!?!? I would suggest NORMALIZATION (eg: create a table please, a table with COLUMNS TO SUPPORT YOUR DATA)


Unfortunately, you did not take the 30 seconds it takes to read:
http://asktom.oracle.com/tkyte/question_policy.htm

although you checked the box that said "i read it". Read #3....

sigh. no one reads anything anymore. Or if they do, I'm at a loss as to why they do the opposite....


ops$tkyte%ORA10GR2> create table "i hate your 'design'"
  2  ( nm varchar2(30),
  3    c1 varchar2(23),
  4    c2 varchar2(15)
  5  )
  6  /

Table created.

ops$tkyte%ORA10GR2> insert into "i hate your 'design'" (nm,c1,c2) values ( 'Martin','ChequeNo=929020','Value=2000' );

1 row created.

ops$tkyte%ORA10GR2> insert into "i hate your 'design'" (nm,c1,c2) values ( 'Martin','HouseNo=27','State=TamilNadu');

1 row created.

ops$tkyte%ORA10GR2> insert into "i hate your 'design'" (nm,c1,c2) values ( 'Martin','BankName=Bank of Baroda', 'Branch=T Nagar' );

1 row created.

ops$tkyte%ORA10GR2> insert into "i hate your 'design'" (nm,c1,c2) values ( 'Luther','ChequeNo=922320','Value=2400' );

1 row created.

ops$tkyte%ORA10GR2> insert into "i hate your 'design'" (nm,c1,c2) values ( 'Luther','BankName=UBS','Branch=Zurich' );

1 row created.

ops$tkyte%ORA10GR2> insert into "i hate your 'design'" (nm,c1,c2) values ( 'Shankar','ChequeNo=929590','Value=1200' );

1 row created.

ops$tkyte%ORA10GR2>
ops$tkyte%ORA10GR2> select nm,
  2         max( decode(rn,1,c1) ) c1_1,
  3         max( decode(rn,1,c2) ) c2_1,
  4         max( decode(rn,2,c1) ) c1_2,
  5         max( decode(rn,2,c2) ) c2_2,
  6         max( decode(rn,3,c1) ) c1_3,
  7         max( decode(rn,3,c2) ) c2_3,
  8         max( decode(rn,4,c1) ) c1_4,
  9         max( decode(rn,4,c2) ) c2_4,
 10         max( decode(rn,5,c1) ) c1_5,
 11         max( decode(rn,5,c2) ) c2_5,
 12         max( decode(rn,6,c1) ) c1_6,
 13         max( decode(rn,6,c2) ) c2_6
 14    from (
 15  select nm, c1, c2, row_number() over (partition by nm order by rowid) rn
 16    from "i hate your 'design'"
 17         )
 18   group by nm
 19  /

NM                             C1_1                    C2_1            C1_2                    C2_2            C1_3                    C2_3            C1_4                 C2_4            C1_5                    C2_5            C1_6                    C2_6
------------------------------ ----------------------- --------------- ----------------------- --------------- ----------------------- --------------- ----------------------- --------------- ----------------------- --------------- ----------------------- ---------------
Luther                         ChequeNo=922320         Value=2400      BankName=UBS            Branch=Zurich
Martin                         ChequeNo=929020         Value=2000      HouseNo=27              State=TamilNadu BankName=Bank of Baroda Branch=T Nagar
Shankar                        ChequeNo=929590         Value=1200




if you think "5 will be the most", then create a view like the above with 7 sets (I used 6 sets in my EXAMPLE).

If you think "10 will be the most", then use 12 - whatever.

and if the 'developers' (and I use the word loosely here) cannot tell you what the max would be - show them this query and tell them "construct THIS - do not join N times"

Rating

  (4 ratings)

Is this answer out of date? If it is, please let us know via a Comment

Comments

Converting Vertical Rows Into Horizontal Rows

Hariharan Sairam Titai, September 07, 2009 - 3:27 am UTC

Hi Tom,

I sincerely apologize Tom for not providing the details as provided in Point Number 3 of your policy.

I was in a hurry to type the question.

I will never repeat this mistake again

Sorry please...

Hari

Normalization

karthick, September 07, 2009 - 3:56 am UTC

hari,

From whatever sample data you have given it looks like you have mixed up Master and transaction information into a single table.

Check No and Value looks like Transaction information. And HouseNo, State, BankName, Branch looks like Master information.

When you store master data with transaction data you tend to create redundant data. So its better for your developers to read the Theory of Normalization to know what all they need to consider while designing a table.

Thanks,
Karthick.



Tom Kyte
September 07, 2009 - 6:51 am UTC

.... while designing a table ...

ahh, but you see - they skipped that part entirely.

Normalization

Hariharan Sairam Titai, September 07, 2009 - 4:08 am UTC

Karthick,

Thanks for this information.

However, I was not involved when a design was made. I am very much new to this company, and one of my job profiles is to solve all the current issues in the database.

Thanks again

Hari

mdjnr, September 08, 2009 - 4:53 pm UTC

I would say, the best way to "solve all the current issues in the database" would be to redesign the database in a normalized fashion and to get some competent developers!

More to Explore

Analytics

Analytic SQL got you confused? Check out Connor McDonald's complete video course.