1

Okay so say I have something like this:

ID | Name | Address
 1 | Bob  | 123 Fake Street
 1 | Bob  | 221 Other Street

done by doing something like:

select p.ID, p.Name a.Address from People p 
inner join Addresses a on a.OwnerID = p.ID

Is there any way to turn that into

ID | Name |    Address_1    |     Address_2    | etc...
 1 | Bob  | 123 Fake Street | 221 Other street | etc

I've seen things that do comma separated values in one column but I don't want that I want distinct columns. I am querying this using MSSQL and C# I don't know if that changes anything. Also this is a made up scenario that is just similar to what I'm doing so the actual structure of the tables can't be changed.

Anyone have any suggestions?

2
  • Why you need columns? Are you loading data into DataTable and showing it in some grid control? Commented Jun 13, 2013 at 13:11
  • yeah it could potentially be passed to a DataTable. But right now the values are being used to load up an object. I just don't want a bunch of special cases in my code checking for the similar ID and then parsing it. I want to make it as general as possible Commented Jun 13, 2013 at 13:14

1 Answer 1

4

You can use the PIVOT function to get the result but you will also have to implement using a row_number() so you can convert multiple addresses per person into columns.

If you had a known number of addresses, then you would hard-code the query:

select id, name, address_1, address_2
from
(
  select p.id, p.name, a.address,
    'Address_'+cast(row_number() over(partition by p.id 
                                      order by a.ownerid) as varchar(10)) rn
  from people p
  inner join addresses a
    on p.id = a.ownerid
) d
pivot
(
  max(address)
  for rn in (address_1, address_2)
) piv;

See SQL Fiddle with Demo.

But if your case, you will have an unknown number of addresses per person so you will want to use dynamic SQL and place it into a stored procedure to execute:

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

select @cols = STUFF((SELECT distinct ',' + QUOTENAME('Address_'+d.rn) 
                    from 
                    (
                      select cast(row_number() over(partition by a.ownerid
                                      order by a.ownerid) as varchar(10)) rn
                      from Addresses a
                    ) d
            FOR XML PATH(''), TYPE
            ).value('.', 'NVARCHAR(MAX)') 
        ,1,1,'')

set @query = 'SELECT id, name, ' + @cols + ' 
            from
            (
              select p.id, p.name, a.address,
                ''Address_''+cast(row_number() over(partition by p.id 
                                                  order by a.ownerid) as varchar(10)) rn
              from people p
              inner join addresses a
                on p.id = a.ownerid
            ) d
            pivot 
            (
                max(address)
                for rn in (' + @cols + ')
            ) p '

execute(@query);

See SQL Fiddle with Demo. These both give a result:

| ID | NAME |         ADDRESS_1 |        ADDRESS_2 | ADDRESS_3 |
----------------------------------------------------------------
|  1 |  Bob |   123 Fake Street | 221 Other Street |    (null) |
|  2 |  Jim | 123 e main street |           (null) |    (null) |
|  3 |  Tim |   489 North Drive |   56 June Street |  415 Lost |
Sign up to request clarification or add additional context in comments.

6 Comments

One problem I can't create a stored procedure (don't have any permissions except select basically). Is there a way of doing the general way without a stored procedure?
@eric When you are working with dynamic SQL, it has to be implemented in a stored procedure. The problem is that you will have an unknown number of addresses for each person. Do you have a limit on how many addresses a person can have?
no unfortunately it can be any number of addresses. If I did have a limit would I just do the first one with rn in (address_1, address_2, ... address_n)?
@eric Then unfortunately you are left using dynamic SQL. In order to PIVOT like this the values have to be known, so the dynamic sql is generating the list of values prior to the execution of the sql string. There is no other way to do this in SQL.
will this also work if I had Address_Street and Address_Number as separate columns? so it would come out to be Address_Street_1 | Address_Number_1 | etc etc
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.