Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

SQL: Real Transpose

I know about pivot and unpivot. That is not what I want. Pivot and unpivot aggregate data, but that is not what I want.

Think of a table as a matrix (linear algebra). If I start with an m x n matrix, I want to convert that matrix (table) into an n x m matrix. I want a true TRANSPOSE.

How can I do this in SQL?

For example if I have:

1  2  3
1  2  4
6  7  8
3  2  1
3  9  1

then the result should be:

1  1  6  3  3
2  2  7  2  9
3  4  8  1  1

Notice that the number of rows becomes the number of columns, and vice versa. Also notice that I have not grouped or aggregated any of the data. Every single value present in the source is present in the result, and their x-y coordinates have been swapped.

like image 719
mtmurdock Avatar asked Oct 02 '12 18:10

mtmurdock


People also ask

Is there a transpose function in SQL?

Using a T-SQL Pivot function is one of the simplest method for transposing rows into columns.

How do I display horizontal data vertically in SQL?

The purpose of the PIVOT query is to rotate the output and display vertical data horizontally. These queries are also known as crosstab queries. The SQL Server PIVOT operator can be used to easily rotate/transpose your data. This is a very nice tool if the data values that you wish to rotate are not likely to change.


1 Answers

I am unsure why you think you cannot accomplish this with an UNPIVOT and a PIVOT:

select [1], [2], [3], [4], [5]
from 
(
  select *
  from
  (
    select col1, col2, col3,
      row_number() over(order by col1) rn
    from yourtable
  ) x
  unpivot
  (
    val for col in (col1, col2, col3)
  ) u
) x1
pivot
(
  max(val)
  for rn in ([1], [2], [3], [4], [5])
) p

See SQL Fiddle with Demo. This could also be performed dynamically if needed.

Edit, if the column order needs to be kept, then you can use something like this, which applies the row_number() without using a order by on one of the columns in your table (here is an article about using non-deterministic row numbers):

select [1], [2], [3], [4], [5]
from 
(
  select *
  from
  (
    select col1, col2, col3,
      row_number() 
        over(order by (select 1)) rn
    from yourtable
  ) x
  unpivot
  (
    val for col in (col1, col2, col3)
  ) u
) x1
pivot
(
  max(val)
  for rn in ([1], [2], [3], [4], [5])
) p;

See SQL Fiddle with Demo

like image 82
Taryn Avatar answered Nov 15 '22 05:11

Taryn