views:

45

answers:

3

Hello,

I've got a table in database that looks like this:

CustomerId    Attribute    Value
================================
30            Name         John
30            Surname      Smith
30            Phone        555123456

to make some use of the data I need to make it look sth. like this:

CustomerId    Name    Surname    Phone
======================================
30            John    Smith      555123456

I know I can create stored procedure or table-valued function that will do it for me, but I'm wondering what would be the best choice here? Maybe I can do it with some clever sql select query only?

+4  A: 

If this is SQL Server 2005 or later, you can use PIVOT:

with Customers (CustomerId, Attribute, Value)
as
(
    select 30, 'Name', 'John'
    union
    select 30, 'Surname', 'Smith'
    union
    select 30, 'Phone', '551123456'
    union
    select 40, 'Name', 'Mary'
    union
    select 40, 'Surname', 'Johnson'
    union
    select 40, 'Phone', '9991111234'
)
select CustomerId, Name, Surname, Phone
from Customers
pivot
(
    min(Value)
    for Attribute in (Name, Surname, Phone)
) as PivotTable

Or a solution that does not use PIVOT:

/* with cte defined as above */
select CustomerId, 
    max(case Attribute when 'Name' then Value else '' end) Name,
    max(case Attribute when 'Surname' then Value else '' end) Surname,
    max(case Attribute when 'Phone' then Value else '' end) Phone
from Customers
group by CustomerId
adrift
Thank you very much! That's an answer I couldn't even have dreamt of!
kubal5003
+1  A: 

Sounds like you need to PIVOT. You should read the following article to learn how to do that:

PIVOT functionality in SQL Server

Michael Goldshteyn
+1  A: 

Given the following scenario:

create table vertical(
CustomerID int, 
attribute varchar(255),
value varchar(255)
)

create table horizontal(
CustomerID int, 
name varchar(255),
surname varchar(255),
phone varchar(255)
)

insert into vertical
    select 30, 'Name', 'John'
insert into vertical
    select 30, 'Surname', 'Smith'
insert into vertical
    select 30, 'Phone', '551123456'
insert into vertical
    select 40, 'Name', 'Mary'
insert into vertical
    select 40, 'Surname', 'Johnson'
insert into vertical
    select 40, 'Phone', '9991111234'
insert into vertical
    select 50, 'Surname', 'Manuel'
insert into vertical
    select 50, 'Phone', '423'

running this insert

insert into horizontal (CustomerID, name, surname, phone)
select c.CustomerID, n.value as name, s.value as surname, ph.value as phone 
from 
 (select distinct CustomerID from vertical) as c
left join vertical n
    on c.CustomerID = n.CustomerID and n.attribute = 'name'
left join vertical s
    on c.CustomerID = s.CustomerID and s.attribute = 'Surname'
left join vertical ph
    on c.CustomerID = ph.CustomerID and ph.attribute = 'Phone'

shall output this:

ID  Name    Surname Phone
--  ----    ------- -----
30  John    Smith   551123456
40  Mary    Johnson 9991111234
50  NULL    Manuel  423

Where:

from: select distinct CustomerID from vertical brings all customers that have at least one attribute.

each left join returns the corresponding value for each attribute.

left join was used to ensure that the customer row will be inserted even if the customer is missing some attributes in which case NULL will be inserted.

source table named vertical is the one with the attribute values

target table named horizontal is your desired output

Dimitris Baltas
Thanks, self join was always some kind of option, but I personally don't like it, because it's ugly. Pivot appears to be a whole lot better solution.
kubal5003