5

Suppose I have this table:

Create table test(a int, b int, c int, d int)

I can write simply 'select * from test' to get the following first record:

A    B    C    D  
1    2    3    4

But instead, I want it like this (Four rows for single record):

A: 1  
B: 2  
C: 3  
D: 4

Can someone help me in doing this?

This is required to view a single record on remote desktop system which is extremely slow, and horizontal scrolling on it sucks, and has 800 columns in it. So I need to see the format of data from a single record.

Taryn
  • 242,637
  • 56
  • 362
  • 405
teenup
  • 7,459
  • 13
  • 63
  • 122
  • Depends on which SQL tool (client) you are using. Some can do that directly. –  Dec 12 '12 at 13:06
  • I have sql server management studio 2008 – teenup Dec 12 '12 at 13:07
  • I assume you have multiple rows in your table? If so, then you'll expect to multiple the number of expanded rows by the number of columns involved in the query, right? Also, you want the result in genuine rows and not just a row with (say) newlines? – RonaldBarzell Dec 12 '12 at 13:11
  • I just need data from one record. Not all. – teenup Dec 12 '12 at 13:17

1 Answers1

12

You can use the UNPIVOT function to do this, the version below concatenates the column name and value together, but you can always display them as separate columns:

select col+':'+cast(value as varchar(10)) col
from test
unpivot
(
  value
  for col in (A, B, C, D)
) unpiv

See SQL Fiddle with Demo

The above works great if you have a known number of columns, but if you have 800 columns that you want to transform, you might want to use dynamic sql to perform this:

DECLARE @colsUnpivot AS NVARCHAR(MAX),
    @query  AS NVARCHAR(MAX)

select @colsUnpivot = stuff((select ','+quotename(C.name)
         from sys.columns as C
         where C.object_id = object_id('test')
         for xml path('')), 1, 1, '')

set @query 
  = 'select col+'':''+cast(value as varchar(10)) col
     from test
     unpivot
     (
       value
       for col in ('+ @colsunpivot +')
     ) u'

exec(@query)

See SQL Fiddle with Demo

Note: when using UNPIVOT the datatypes of all of the columns that need to be transformed must be the same. So you might have to cast/convert data as needed.

Edit #1, since your datatypes are different on all of your columns and you need to unpivot them, then you can use the following code.

The first piece get the list of columns that you want to unpivot dynamically:

select @colsUnpivot = stuff((select ','+quotename(C.name)
             from sys.columns as C
             where C.object_id = object_id('test')
             for xml path('')), 1, 1, '')

The second piece gets the same list of columns but wraps each column in a cast as a varchar:

select @colsUnpivotCast = stuff((select ', cast('+quotename(C.name)+' as varchar(50)) as '+quotename(C.name)
         from sys.columns as C
         where C.object_id = object_id('test')
         for xml path('')), 1, 1, '')

Then your final query will be:

DECLARE @colsUnpivot AS NVARCHAR(MAX),
    @colsUnpivotCast AS NVARCHAR(MAX),
    @query  AS NVARCHAR(MAX)


select @colsUnpivot = stuff((select ','+quotename(C.name)
         from sys.columns as C
         where C.object_id = object_id('test')
         for xml path('')), 1, 1, '')

select @colsUnpivotCast = stuff((select ', cast('+quotename(C.name)+' as varchar(50)) as '+quotename(C.name)
         from sys.columns as C
         where C.object_id = object_id('test')
         for xml path('')), 1, 1, '')


set @query 
  = 'select col+'':''+value col
     from
    (
      select '+@colsUnpivotCast+'
      from test
    ) src
     unpivot
     (
       value
       for col in ('+ @colsunpivot +')
     ) u'


exec(@query)

See SQL Fiddle with Demo

The UNPIVOT function is performing the same process as a UNION ALL which would look like this:

select col+':'+value as col
from
(
  select A value, 'A' col
  from test
  union all
  select cast(B as varchar(10)) value, 'B' col
  from test
  union all
  select cast(C as varchar(10)) value, 'C' col
  from test
  union all
  select cast(D as varchar(10)) value, 'D' col
  from test
) src

See SQL Fiddle with Demo

The result of all of the queries is the same:

|    COL |
----------
|    A:1 |
| B:2.00 |
|    C:3 |
|    D:4 |

Edit #2: using UNPIVOT strips out any of the null columns which could cause some data to drop. If that is the case, then you will want to wrap the columns with IsNull() to replace the null values:

DECLARE @colsUnpivot AS NVARCHAR(MAX),
    @colsUnpivotCast AS NVARCHAR(MAX),
    @query  AS NVARCHAR(MAX)


select @colsUnpivot = stuff((select ','+quotename(C.name)
         from sys.columns as C
         where C.object_id = object_id('test')
         for xml path('')), 1, 1, '')

select @colsUnpivotCast = stuff((select ', IsNull(cast('+quotename(C.name)+' as varchar(50)), '''') as '+quotename(C.name)
         from sys.columns as C
         where C.object_id = object_id('test')
         for xml path('')), 1, 1, '')


set @query 
  = 'select col+'':''+value col
     from
    (
      select '+@colsUnpivotCast+'
      from test
    ) src
     unpivot
     (
       value
       for col in ('+ @colsunpivot +')
     ) u'


exec(@query)

See SQL Fiddle with Demo

Replacing the null values, will give a result like this:

|    COL |
----------
|    A:1 |
| B:2.00 |
|     C: |
|    D:4 |
Taryn
  • 242,637
  • 56
  • 362
  • 405
  • Do I need to write down all 800 columns like this in unpivot clause? – teenup Dec 12 '12 at 13:10
  • @puretechy I just edited this with a dynamic version as well. – Taryn Dec 12 '12 at 13:12
  • Where I need to use the cast, there are 800 columns, I need to cast all into nvarchar. Havn't you already used cast here? I have never used PIVOT and right now unable to understand this. – teenup Dec 12 '12 at 13:20
  • How do I cast all into VARCHAR in this? Receiving this error- "The type of column "USR_USER_ID" conflicts with the type of other columns specified in the UNPIVOT list." – teenup Dec 12 '12 at 13:27
  • Are the data types different for each column? – Taryn Dec 12 '12 at 14:03
  • Yes, the data types are different, I have 800 columns – teenup Dec 12 '12 at 14:34
  • @puretechy see my edit, you can still use a dynamic version to cast each column. – Taryn Dec 12 '12 at 14:41
  • Thanks, this is great! But I am getting less number of columns than I actually have in table. In a table with 16 columns, I am getting 14 rows only. – teenup Dec 12 '12 at 16:13
  • @puretechy if the data contains null values then those are not included, you will have to wrap the columns with `IsNull()` around the columns to replace any nulls with an empty string or some other value. See my edit. – Taryn Dec 12 '12 at 16:38