HOW TO TRANSPOSE A TABLE THROUGH COMPACT SQL CODING

DOWNLOAD THE PDF HERE

In relational data analysis, sometimes we want to convert the table columns to rows and rows to columns. For instance, the following table (Table A) shows the score by course (column) for each student (row). In this case, STUDENT is the key field for a record, The courses: ARTSCHEMISTRY and PHYSICS are the attributes of a STUDENTrecord, with scores as field values respectively.

Table A:

 

STUDENT ARTS CHEMISTRY PHYSICS
A001 65 95 90
A002 88 70 85
A003 92 93 67
A004 82 89 77

The resulting clustered bar chart looks like this:

 

On some occasions, we want to analyze the scores by student (column) for each course (row), as shown in Table B. Now the key field is COURSE, and the students: A001A002A003, A004 become attributes of a COURSE record.

Table B:

 

COURSE A001 A002 A003 A004
Arts 65 88 92 82
Chemistry 95 70 93 89
Physics 90 85 67 77
         

The resulting clustered bar chart is like this:

 

Comparing to Table A, Table B is the transpose of Table A. The question is: how to convert from Table A to Table B? There are many approaches to achieve this goal. Today we are introducing the most compact and easiest way—using UNPIVOT and PIVOT functions in one script.

UNPIVOT Operator

UNPIVOT operator converts columns to rows. Below is the syntax:

SELECT [columns]

FROM [table “” not found /]

UNPIVOT [INCLUDE | EXCLUDE NULLS]

(

    unpivot_clause

    for_clause

    in_clause

);

In this syntax:

 

  • The optional INCLUDE | EXCLUDE NULLS clause allows you to include or exclude null-valued rows.
  • The unpivot_clause specifies a new column name that represents the measured values after unpivot.
  • The unpivot_for_clause specifies a new column name that will define the initial column names.
  • The unpivot_in_clause contains the names of all columns as row values after unpivoted.

PIVOT Operator

PIVOT operator converts rows to columns. Below is the syntax:

SELECT [columns]

FROM [table “” not found /]

PIVOT

(

    pivot_clause

    for_clause

    in_clause

);

In this syntax:

 

  • pivot_clause specifies the column(s) that you want to aggregate.
    • The pivot_clause performs an implicitly GROUP BY based on the values provided by the pivot_in_clause and non-pivoted column(s).
    • The reason for aggregation is because it is possible there are multiple rows with the same value as the transposed column name.
  • pivot_for_clause specifies the column that you want to group or pivot.
  • pivot_in_clause defines a filter for column(s) in the pivot_for_clause. Each distinct value in the pivot_in_clause will be converted into a separate column.

For more details about the syntax of UNPIVOT and PIVOT, please refer to the following two articles:

 

https://www.oracletutorial.com/oracle-basics/oracle-unpivot/

 

https://www.oracletutorial.com/oracle-basics/oracle-pivot/

Let’s see how these two operators work in our examples. First, we build a quick data view called “student_score” to simulate the Table A

SELECT ‘A001’ student, 65 arts, 95 chemistry, 90 physics FROM dual

UNION ALL

SELECT ‘A002’ student, 88 arts, 70 chemistry, 85 physics FROM dual

UNION ALL

SELECT ‘A003’ student, 92 arts, 93 chemistry, 67 physics FROM dual

UNION ALL

SELECT ‘A004’ student, 82 arts, 89 chemistry, 77 physics FROM dual

After applying the UNPIVOT clause, the SQL script looks like this:

WITH student_score AS

(

SELECT ‘A001’ student, 65 arts, 95 chemistry, 90 physics FROM dual

UNION ALL

SELECT ‘A002’ student, 88 arts, 70 chemistry, 85 physics FROM dual

UNION ALL

SELECT ‘A003’ student, 92 arts, 93 chemistry, 67 physics FROM dual

UNION ALL

SELECT ‘A004’ student, 82 arts, 89 chemistry, 77 physics FROM dual

)

SELECT * from student_score

UNPIVOT

(

score                         –unpivot_clause

FOR course               –for_clause

IN (                             –in_clause

arts as ‘Arts’,

chemistry as ‘Chemistry’,

physics as ‘Physics’

)

)

The result set after execution is:

 

STUDENT COURSE SCORE
A001 Arts 65
A001 Chemistry 95
A001 Physics 90
A002 Arts 88
A002 Chemistry 70
A002 Physics 85
A003 Arts 92
A003 Chemistry 93
A003 Physics 67
A004 Arts 82
A004 Chemistry 89
A004 Physics 77

The course column names become value of the Course column after the UNPIVOT operation.

Let’s see how the table will look like if we apply the PIVOT clause right after the UNPIVOT. There are two options to apply the PIVOT clause after the UNPIVOT clause. However, the result will be different.

Option 1: Aggregate for “course”.

WITH student_score AS

(

SELECT ‘A001’ student, 65 arts, 95 chemistry, 90 physics FROM dual

UNION ALL

SELECT ‘A002’ student, 88 arts, 70 chemistry, 85 physics FROM dual

UNION ALL

SELECT ‘A003’ student, 92 arts, 93 chemistry, 67 physics FROM dual

UNION ALL

SELECT ‘A004’ student, 82 arts, 89 chemistry, 77 physics FROM dual

)

SELECT * from student_score

UNPIVOT

(

score                         –unpivot_clause

FOR course               –for_clause

IN (                             –in_clause

arts as ‘Arts’,

chemistry as ‘Chemistry’,

physics as ‘Physics’

)

)

PIVOT

(

SUM (score)             — pivot_clause

FOR course               — pivot_ for_clause

IN (                             — pivot_ in_clause

‘Arts’ as arts,

‘Chemistry’ as chemistry,

‘Physics’ as physics

)

)

The result set is

 

STUDENT ARTS CHEMISTRY PHYSICS
A001 65 95 90
A002 88 70 85
A003 92 93 67
A004 82 89 77

Have readers discovered the interim table is rolled back to Table A? This is self-explanatory, since the UNPIVOT and PIVOT clauses are sharing the same fields, so there are offset to each other.

Option 2: Aggregate for “student”.

WITH student_score AS

(

SELECT ‘A001’ student, 65 arts, 95 chemistry, 90 physics FROM dual

UNION ALL

SELECT ‘A002’ student, 88 arts, 70 chemistry, 85 physics FROM dual

UNION ALL

SELECT ‘A003’ student, 92 arts, 93 chemistry, 67 physics FROM dual

UNION ALL

SELECT ‘A004’ student, 82 arts, 89 chemistry, 77 physics FROM dual

)

SELECT * from student_score

UNPIVOT

(

score                         –unpivot_clause

FOR course               –for_clause

IN (                             –in_clause

arts as ‘Arts’,

chemistry as ‘Chemistry’,

physics as ‘Physics’

)

)

PIVOT

(

SUM (score)             — pivot_clause

FOR student             — pivot_ for_clause

IN (                             — pivot_ in_clause

‘A001’ as A001,

‘A002’ as A002,

‘A003’ as A003,

‘A004’ as A004

)

)

The result set is

 

COURSE A001 A002 A003 A004
Arts 65 88 92 82
Chemistry 95 70 93 89
Physics 90 85 67 77

Comparing to Table A, the columns become rows and rows become columns. This is the transpose of Table A, which is our desired result!

Summary:

PIVOT and UNPIVOT in SQL are two relational operators to convert a table into each other. Using PIVOT and UNPIVOT in a SQL script properly can facilitate data analytics or multidimensional reporting. With easy-understanding and compact script structure, it also improves the SQL development lifecycle with better efficiency and fewer errors.