lakshminb7
lakshminb7

Reputation: 1602

Select and merge rows in a table in SQL Stored procedure

Have a temp table with schema: ID | SeqNo | Name

ID - Not unique
SeqNo - Int (can be 1,2 or 3). Sort of ID+SeqNo as Primary key
Name - Any text

And sample data in the table like this

1 | 1 | RecordA  
2 | 1 | RecordB  
3 | 1 | RecordC  
1 | 2 | RecordD  
4 | 1 | RecordE  
5 | 1 | RecordF  
3 | 1 | RecordG  

Need to select from this table and output like

1 | RecordA/RecordD  
2 | RecordB  
3 | RecordC/RecordG  
4 | RecordE  
5 | RecordF  

Need to do this without cursor.

Upvotes: 0

Views: 3186

Answers (3)

himaja
himaja

Reputation: 1

The solution is good. I have a similar issue, but here I am using 2 different tables. ex:

table1 

1 | 1 |
2 | 3 |
3 | 1 |
4 | 2 |
5 | 1 |
1 | 2 |
1 | 3 | 
4 | 1 |
5 | 2 |
2 | 2 |
4 | 3 |

table2 
1 | RecordA
2 | RecordB
3 | RecordC

I want to get the data from two tables and display in the below format.

1 | RecordA,RecordB,RecordC|
2 | RecordB,RecordC|
3 | RecordA |
4 | RecordA,RecordB,RecordC|
5 | RecordA,RecordB | 

Upvotes: 0

Peter Radocchia
Peter Radocchia

Reputation: 11007

If you know SeqNo will never be more than 3:

select Id, Names = stuff(
    max(case when SeqNo = 1 then '/'+Name else '' end)
  + max(case when SeqNo = 2 then '/'+Name else '' end)
  + max(case when SeqNo = 3 then '/'+Name else '' end)
  , 1, 1, '')
from table1 
group by Id

Otherwise, something like this is the generic solution to an arbitrary number of items:

select Id, Names = stuff((
  select '/'+Name from table1 b
  where a.Id = b.Id order by SeqNo
  for xml path (''))
  , 1, 1, '')
from table1 a
group by Id

Or write a CLR UDA.

Edit: had the wrong alias on the correlated table!

Edit2: another version, based on Remus's recursion example. I couldn't think of any way to select only the last recursion per Id, without aggregation or sorting. Anybody know?

;with
  myTable as (
    select * from (
      values 
        (1, 1, 'RecordA')  
      , (2, 1, 'RecordB')  
      , (3, 1, 'RecordC')  
      , (1, 2, 'RecordD')  
      , (4, 1, 'RecordE')  
      , (5, 1, 'RecordF')  
      , (3, 2, 'RecordG')
      ) a (Id, SeqNo, Name)
    )    
, anchor as (
    select id, name = convert(varchar(max),name), seqno
    from myTable where seqno=1
    )
, recursive as (
    select id, name, seqno
    from anchor
    union all
    select t.id, r.name + '/' + t.name, t.seqno
    from myTable t
    join recursive  r on t.id = r.id and r.seqno+1 = t.seqno
    )
select id, name = max(name) 
from recursive
group by id;
---- without aggregation, we get 7 rows:
--select id, name
--from recursive;

Upvotes: 3

Remus Rusanu
Remus Rusanu

Reputation: 294277

If SeqNo is limited to 1,2,3:

select id, a.name + coalesce('/'+b.name, '') + coalesce('/'+c.name, '')
from myTable a
left outer join myTable b on a.id=b.id and b.seqno = 2
left outer join myTable c on a.id=c.id and c.seqno = 3
where a.seqno = 1;

If SeqNo is open ended you can deploy a recursive cte:

;with anchor as (
   select id, name, seqno
      from myTable
      where seqno=1)
, recursive as (
   select id, name, seqno
      from anchor
      union all
   select t.id, r.name + '/' + t.name, t.seqno
      from myTable t
      join recursive  r on t.id = r.id and r.seqno+1 = t.seqno)
select id, name from recursive;

Upvotes: 3

Related Questions