Pivot table to turn rows into columns - sql

I currently run the query
SELECT [PriceAttributeID]
,[PriceID]
,[AttributeID]
,[PriceAttributeComparator]
,[PriceAttributeMin]
,[PriceAttributeMax]
FROM [PriceAttribute]
Which gives the output
1 2 1 1 S NULL
2 3 1 1 M NULL
3 4 1 1 L NULL
4 5 1 1 L NULL
5 5 2 1 Black NULL
I would like to get the output (where _Comp, _Min and _Max relate to PriceAttributeComparator, PriceAttributeMin and PriceAttributeMax)
PriceID 1_Comp 1_Min 1_Max 2_Comp 2_Min 2_Max
2 1 S NULL NULL NULL NULL
3 1 M NULL NULL NULL NULL
4 1 L NULL NULL NULL NULL
5 1 L NULL 1 Black NULL
The same query would also be expected to have 1_ and 2_ prefixes as 4_, 5_, 19_ and 32_ or any other indeterminate number of ID's based on what is in the table at the time.
I have attempted a PIVOT table, but i am new to them and haven't the first clue on how to create what it is i am looking to do.

Part of the problem you are probably having with the PIVOT function is due to the fact you have multiple columns that you want to apply the function to. If you want to use the PIVOT function, then I would suggest first unpivoting the columns PriceAttributeComparator, PriceAttributeMin and PriceAttributeMax. When you unpivot the data you will no longer have multiple columns, you will have multiple rows, then you can apply the pivot to all of the appropriate values.
You did not specify what version of SQL Server you are using but you can use CROSS APPLY with a UNION ALL to unpivot the columns:
select priceid,
col = cast(attributeid as varchar(10))+'_'+ col,
value
from
(
select PriceID,
AttributeID,
comp = cast(PriceAttributeComparator as varchar(10)),
[min] = cast(PriceAttributeMin as varchar(10)),
[max] = cast(PriceAttributeMax as varchar(10))
from PriceAttribute
) d
cross apply
(
select 'comp', comp union all
select 'min', [min] union all
select 'max', [max]
) c (col, value)
See Demo. This process will convert your data into the following format:
| PRICEID | COL | VALUE |
-----------------------------
| 2 | 1_comp | 1 |
| 2 | 1_min | S |
| 2 | 1_max | (null) |
| 3 | 1_comp | 1 |
| 3 | 1_min | M |
| 3 | 1_max | (null) |
Once the data is in multiple rows, then you can apply the PIVOT function to the values in col:
select priceid,
[1_comp], [1_min], [1_max], [2_comp], [2_min], [2_max]
from
(
select priceid,
col = cast(attributeid as varchar(10))+'_'+ col,
value
from
(
select PriceID,
AttributeID,
comp = cast(PriceAttributeComparator as varchar(10)),
[min] = cast(PriceAttributeMin as varchar(10)),
[max] = cast(PriceAttributeMax as varchar(10))
from PriceAttribute
) d
cross apply
(
select 'comp', comp union all
select 'min', [min] union all
select 'max', [max]
) c (col, value)
) src
pivot
(
max(value)
for col in ([1_comp], [1_min], [1_max], [2_comp], [2_min], [2_max])
) piv;
See SQL Fiddle with Demo.
The above versions work great if you have a known number of values but if the values are unknown, then you will need to use dynamic SQL to get the result:
DECLARE #cols AS NVARCHAR(MAX),
#query AS NVARCHAR(MAX)
select #cols = STUFF((SELECT ',' + QUOTENAME(cast(attributeid as varchar(10))+'_'+ col)
from
(
select distinct attributeid
from priceattribute
) d
cross apply
(
select 'comp', 1 union all
select 'min', 2 union all
select 'max', 3
) c (col, so)
group by attributeid, col, so
order by attributeid, so
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)')
,1,1,'')
set #query = 'SELECT priceid, ' + #cols + '
from
(
select priceid,
col = cast(attributeid as varchar(10))+''_''+ col,
value
from
(
select PriceID,
AttributeID,
comp = cast(PriceAttributeComparator as varchar(10)),
[min] = cast(PriceAttributeMin as varchar(10)),
[max] = cast(PriceAttributeMax as varchar(10))
from PriceAttribute
) d
cross apply
(
select ''comp'', comp union all
select ''min'', [min] union all
select ''max'', [max]
) c (col, value)
) x
pivot
(
max(value)
for col in (' + #cols + ')
) p '
execute sp_executesql #query;
See SQL Fiddle with Demo. These solutions will give a result:
| PRICEID | 1_COMP | 1_MIN | 1_MAX | 2_COMP | 2_MIN | 2_MAX |
----------------------------------------------------------------
| 2 | 1 | S | (null) | (null) | (null) | (null) |
| 3 | 1 | M | (null) | (null) | (null) | (null) |
| 4 | 1 | L | (null) | (null) | (null) | (null) |
| 5 | 1 | L | (null) | 1 | Black | (null) |

It might be simplest to do this using conditional aggregation rather than pivot:
SELECT PriceID,
max(case when AttributeID = 1 then PriceAttributeComparator end) as comp_1,
max(case when AttributeID = 1 then PriceAttributeMin end) as min_1,
max(case when AttributeID = 1 then PriceAttributeMax end) as max_1,
max(case when AttributeID = 2 then PriceAttributeComparator end) as comp_2,
max(case when AttributeID = 2 then PriceAttributeMin end) as min_2,
max(case when AttributeID = 2 then PriceAttributeMax end) as max_2
FROM PriceAttribute pa
group by PriceId;

Related

SQL Transpose row to columns

I am trying to transpose rows to columns but I didn't find any good answers.
Here is an example of what I want:
Input tables:
TABLE A
ID | NAME
1 | BOB
2 | JIM
3 | ROB
TABLE B
ID | CLUB
1 | 2
1 | 3
1 | 4
2 | 2
2 | 1
3 | 5
OUTPUT will be:
ID | CLUB1 | CLUB2 | CLUB3
1 | 2 | 3 | 4
2 | 2 | 1 |
3 | 5 | |
You need to enumerate the values to pivot them:
select id,
max(case when seqnum = 1 then club end) as club_1,
max(case when seqnum = 2 then club end) as club_2,
max(case when seqnum = 3 then club end) as club_3
from (select b.*,
row_number() over (partition by id order by club) as seqnum
from b
) b
group by id;
use conditional aggregation
select id,
max(case when id=1 then club end) club1,
max(case when id=2 then club end) club2,
max(case when id=3 then club end) club3
from tablename
group by id
use case when
select a.id,max(case when name='BOB' then CLUB end) ,
max(case when name='JIM' then CLUB end),
max(case when name='ROB' then CLUB end)
tablea a join tableb b on a.id=b.id group by a.id
Sample Data
IF OBJECT_ID('tempdb..#TempTab')IS NOT NULL
DROP TABLE #TempTab
;WITH CTE (ID,CLUB)
AS
(
SELECT 1 , 2 UNION ALL
SELECT 1 , 3 UNION ALL
SELECT 1 , 4 UNION ALL
SELECT 2 , 2 UNION ALL
SELECT 2 , 1 UNION ALL
SELECT 3 , 5
)
SELECT ID,
CLUB,
'CLUB'+CAST(ROW_NUMBER()OVER(PARTITION BY ID ORDER BY ID) AS VARCHAR) AS CLUBData
INTO #TempTab
FROM CTE
Dynamic sql
DECLARE #Column nvarchar(1000),#Column2 nvarchar(max),
#Sql nvarchar(max)
SELECT #Column =STUFF((SELECT DISTINCT ', '+QUOTENAME(CLUBData)
FROM #TempTab FOR XML PATH ('')),1,1,'')
SET #Sql = 'SELECT Id,'+#Column +'
FROM
(
SELECT * FROM #TempTab
) AS SRc
PIVOT
(
MAX(CLUB) FOR CLUBData IN ('+#Column+')
) AS pvt
'
PRINT #Sql
EXEC (#Sql)
Result
Id CLUB1 CLUB2 CLUB3
-------------------------
1 3 4 2
2 1 2 NULL
3 5 NULL NULL

How distribute SQL results horizontally?

I have a table in SQL Server like this(all columns are numerics):
Id1 | Id2 | Number | Qty
----+-----+--------+-------
1 | 1 | 100001 | 100
1 | 2 | 100002 | 110
1 | 3 | 100003 | 120
2 | 1 | 100004 | 130
2 | 2 | 100005 | 200
2 | 3 | 100006 | 300
2 | 4 | 100007 | 400
and i want the result distributed in 2 more columns, like this (without Id's):
Number1 | Qty1 | Number2 | Qty2 | Number3 | Qty3
--------+-------|---------|-------|---------|------
100001 | 100 | 100002 | 110 | 100003 | 120
100004 | 130 | 100005 | 200 | 100006 | 300
100007 | 400 | null | null | null | null
Is it possible?
Thanks.
You can try something like this:
SELECT CASE WHEN id2 = 1 THEN number ELSE '' END AS 'Number1',
CASE WHEN id2 = 1 THEN Qty ELSE '' END AS 'Qty1',
CASE WHEN id2 = 2 THEN number ELSE '' END AS 'Number2',
CASE WHEN id2 = 2 THEN Qty ELSE '' END AS 'Qty2',
CASE WHEN id2 = 3 THEN number ELSE '' END AS 'Number3',
CASE WHEN id2 = 3 THEN Qty ELSE '' END AS 'Qty3'
FROM tablename
The only thing that comes to mind is a recursive CTE. that will allow you to play with the n values in Id2. Are you sure the Id2 value for your last row is correct with a value of 4?
what do you need is a PIVOT. Here is the link :
https://learn.microsoft.com/en-us/sql/t-sql/queries/from-using-pivot-and-unpivot?view=sql-server-2017
is this useful.?
DECLARE #T AS TABLE
(
id1 INT,
id2 int ,
Number INT,
Qty Int
)
Insert into #T
SELECT 1,1,100001, 100 Union All
SELECT 1,2,100002, 110 Union All
SELECT 1,3,100003, 120 Union All
SELECT 2,1,100004, 130 Union All
SELECT 2,2,100005, 200 Union All
SELECT 2,3,100006, 300 Union All
SELECT 2,4,100007, 400
;with cte1 as
(
select *,
LEAD(Number) OVER(partition by id1 order by id2) as leadingNumber,
LEAD(Qty) OVER(partition by id1 order by id2) as LeadingQty,
ROW_NUMBER()over(partition by id1 order by (select null)) as rowNum
from #T
)
,
cte2
As
(
select
c1.id1,c1.Id2,
c1.Number As Number1,c1.Qty as Qty1,c1.leadingNumber As Number2, c1.LeadingQty as Qty2
,LEAD(leadingNumber) OVER(partition by id1 order by id2) as Number3,
LEAD(LeadingQty) OVER(partition by id1 order by id2) as Qty3
from cte1 c1
)
Select Number1,Qty1,Number2,Qty2,Number3,Qty3
from cte2 where id2%3=1
Ok. After a few researchs, i found a solution to generate dynamic columns and using PIVOT i solved my problem. Thanks to all for the tips.
DECLARE #cols AS NVARCHAR(MAX), #query AS NVARCHAR(MAX), #Param1 AS int
SET #cols = STUFF((SELECT ',' + QUOTENAME(number) FROM View_GRTLinhasGRTLinhasTela WHERE id1 = #Param1 FOR XML PATH(''), TYPE).value('.', 'NVARCHAR(MAX)') ,1,1,'')
SET #query = 'SELECT *
FROM(
SELECT p.number, p.qty FROM View_GRTLinhasGRTLinhasTela p
WHERE p.id1 = #Param1) AS sourcetable
PIVOT (
SUM(qty)
FOR number IN (' + #cols + ') ) AS pivottable'
EXEC sp_executesql #query

SQL Server: Turning rows into columns

I'm trying to make the following structure
ROW | GROUP | ORDER | COL_NAME | VALUE
---------------------------------------------
1 | 10 | 10 | FIRST_COL | Value1
2 | 10 | 10 | FIRST_COL | Value2
3 | 10 | 10 | FIRST_COL | Value3
4 | 10 | 20 | SECOND_COL| Val1
5 | 10 | 20 | SECOND_COL| Val2
6 | 20 | 10 | THIRD_COL | Opt3
...
into
FIRST_COL | SECOND_COL | THIRD_COL
-----------------------------------------------------
Value1 | Val1 | Opt3
Value2 | Val2 |
Value3 | |
What I currently have:
declare #cols varchar(max),
#query varchar(max)
select #cols = stuff((select ',' + quotename([COL_NAME])
from mt
group by [COL_NAME]
for xml path(''), type).value('.', 'varchar(max)'), 1, 1, '');
set #query = 'select ' + #cols + ' from (
select [COL_NAME], [VALUE]
from mt
) x
pivot (
min([VALUE])
for [COL_NAME] in (' + #cols + ')
) p
';
execute(#query);
The current code only shows the minimum values (since it's set to min([VALUES])), so only Value1, Val1 and Opt3 would be shown, but my question here is, how can I modify the code so I get the appropriate table/view?
Thanks!
I believe you need this:
set #query = 'select ' + #cols + ' from (
select [COL_NAME], [VALUE], ROW_NUMBER() OVER (PARTITION BY [COL_NAME] ORDER BY (SELECT NULL)) as seqnum
from mt
) x
pivot (
min([VALUE])
for [COL_NAME] in (' + #cols + ')
) p
';
The pivot uses all the columns in the subquery. You just need one to distinguish among the rows with the same column name.
Something like this?
Declare #YourTable table ([ROW] int,[GROUP] int,[ORDER] int,[COL_NAME] varchar(50),[VALUE] varchar(50))
Insert Into #YourTable Values
(1,10,10,'FIRST_COL' ,'Value1'),
(2,10,10,'FIRST_COL' ,'Value2'),
(3,10,10,'FIRST_COL' ,'Value3'),
(4,10,20,'SECOND_COL','Val1'),
(5,10,20,'SECOND_COL','Val2'),
(6,20,10,'THIRD_COL' ,'Opt3')
;with cteBase as (
Select *
,RowNr = Row_Number() over (Partition By [COL_NAME] Order by [ROW])
From #YourTable
)
Select First_Col = max(case when [COL_NAME]='FIRST_COL' then Value else '' end)
,Second_Col = max(case when [COL_NAME]='SECOND_COL' then Value else '' end)
,Third_Col = max(case when [COL_NAME]='THIRD_COL' then Value else '' end)
From cteBase
Group By RowNr
Returns
First_Col Second_Col Third_Col
Value1 Val1 Opt3
Value2 Val2
Value3
Try it like this:
DECLARE #tbl TABLE([ROW] INT,[GROUP] INT,[ORDER] INT,[COL_NAME] VARCHAR(100),VALUE VARCHAR(100));
INSERT INTO #tbl VALUES
(1,10,10,'FIRST_COL','Value1')
,(2,10,10,'FIRST_COL','Value2')
,(3,10,10,'FIRST_COL','Value3')
,(4,10,20,'SECOND_COL','Val1')
,(5,10,20,'SECOND_COL','Val2')
,(6,20,10,'THIRD_COL','Opt3');
WITH Sorted AS
(
SELECT tbl.*
,ROW_NUMBER() OVER(PARTITION BY tbl.[COL_NAME] ORDER BY tbl.[ROW]) AS SortInx
FROM #tbl AS tbl
)
SELECT MAX(CASE WHEN Sorted.[COL_NAME]='FIRST_COL' THEN Sorted.[VALUE] END) AS FIRST_COL
,MAX(CASE WHEN Sorted.[COL_NAME]='SECOND_COL' THEN Sorted.[VALUE] END) AS SECOND_COL
,MAX(CASE WHEN Sorted.[COL_NAME]='THIRD_COL' THEN Sorted.[VALUE] END) AS THIRD_COL
FROM Sorted
GROUP BY SortInx
As he stated, you need to use RowNumber() to populate your Row column, on your COL_NAME, so your data will look like this.
ROW | GROUP | ORDER | COL_NAME | VALUE
---------------------------------------------
1 | 10 | 10 | FIRST_COL | Value1
2 | 10 | 10 | FIRST_COL | Value2
3 | 10 | 10 | FIRST_COL | Value3
1 | 10 | 20 | SECOND_COL| Val1
2 | 10 | 20 | SECOND_COL| Val2
1 | 20 | 10 | THIRD_COL | Opt3
...
Then, just include the column in your SQL
set #query = 'select [Row], ' + #cols + ' from (
select [Row],[COL_NAME], [VALUE]
from mt
) x
pivot (
min([VALUE])
for [COL_NAME] in (' + #cols + ')
) p
';
execute(#query);
Then, you have
ROW FIRST_COL SECOND_COL THIRD_COL
1 Value1 Val1 Opt3
2 Value2 Val2 NULL
3 Value3 NULL NULL

extend current query, calculated columns

My table looks for example like this:
Name date result
A 2012-01-01 1
A 2012-02-01 2
B 2013-01-01 1
...
For a full example: http://sqlfiddle.com/#!3/0226b/1
At the moment I have a working query that counts the rows by person and year: http://sqlfiddle.com/#!3/0226b/3
This is perfect, but what I want is some extra information for 2014. i need to count how many rows I have for every result.
something like this:
NAME 1 2 3 2014 2013 2012 TOTAL
Person B 4 0 2 6 2 2 10
Person A 2 1 1 4 3 4 11
Person C 1 1 1 3 1 0 4
Even better would be that I give the result-columns a good name (1 = lost, 2= draw, 3=won):
NAME lost draw won 2014 2013 2012 TOTAL
Person B 4 0 2 6 2 2 10
Person A 2 1 1 4 3 4 11
Person C 1 1 1 3 1 0 4
I tried to add some extra code, like:
select #colsResult
= STUFF((SELECT ',' + QUOTENAME(result)
from list
group by result
order by result
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)')
,1,1,'')
I have as result:
,[1]
,[2]
,[3]
But if I run the whole code I get an error, invallid column name...
Since you have two columns that you now want to PIVOT, you'll first have to unpivot those columns and then convert those values into the new columns.
Starting in SQL Server 2005, you could use CROSS APPLY to unpivot the columns. The basic syntax will be similar to:
select
name,
new_col,
total
from
(
select name,
dt = year(date),
result,
total = count(*) over(partition by name)
from list
) d
cross apply
(
select 'dt', dt union all
select 'result', result
) c (old_col_name, new_col)
See SQL Fiddle with Demo. This query gets you a list of names, with the "new columns" and then the Total entries for each name.
| NAME | NEW_COL | TOTAL |
|----------|---------|-------|
| Person A | 2012 | 11 |
| Person A | 1 | 11 |
| Person A | 2012 | 11 |
| Person A | 2 | 11 |
You'll see that the dates and the results are now both stored in "new_col". These values will now be used as the new column names. If you have a limited number of columns, then you would simply hard-code the query:
select name, lost = [1],
draw=[2], won = [3],
[2014], [2013], [2012], Total
from
(
select
name,
new_col,
total
from
(
select name,
dt = year(date),
result,
total = count(*) over(partition by name)
from list
) d
cross apply
(
select 'dt', dt union all
select 'result', result
) c (old_col_name, new_col)
) src
pivot
(
count(new_col)
for new_col in([1], [2], [3], [2014], [2013], [2012])
) piv
order by [2014];
See SQL Fiddle with Demo
Now since your years are dynamic, then you'll need to use dynamic sql. But it appears that you have 3 results and potentially multiple years - so I'd use a combination of static/dynamic sql to make this easier:
DECLARE #cols AS NVARCHAR(MAX),
#query AS NVARCHAR(MAX),
#orderby nvarchar(max)
select #cols
= STUFF((SELECT ',' + QUOTENAME(year(date))
from list
group by year(date)
order by year(date) desc
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)')
,1,1,'')
select #orderby = 'ORDER BY ['+cast(year(getdate()) as varchar(4)) + '] desc'
set #query = 'SELECT name, lost = [1],
draw=[2], won = [3],' + #cols + ', Total
from
(
select
name,
new_col,
total
from
(
select name,
dt = year(date),
result,
total = count(*) over(partition by name)
from list
) d
cross apply
(
select ''dt'', dt union all
select ''result'', result
) c (old_col_name, new_col)
) x
pivot
(
count(new_col)
for new_col in ([1], [2], [3],' + #cols + ')
) p '+ #orderby
exec sp_executesql #query;
See SQL Fiddle with Demo. This gives a result:
| NAME | LOST | DRAW | WON | 2014 | 2013 | 2012 | TOTAL |
|----------|------|------|-----|------|------|------|-------|
| Person B | 7 | 1 | 2 | 6 | 2 | 2 | 10 |
| Person A | 5 | 3 | 3 | 4 | 3 | 4 | 11 |
| Person C | 2 | 1 | 1 | 3 | 1 | 0 | 4 |
If you want to only filter the result columns for the current year, then you can perform this filtering a variety of ways but the easiest you be to include a filter in the unpivot. The hard-coded version would be:
select name, lost = [1],
draw=[2], won = [3],
[2014], [2013], [2012], Total
from
(
select
name,
new_col,
total
from
(
select name,
dt = year(date),
result,
total = count(*) over(partition by name)
from list
) d
cross apply
(
select 'dt', dt union all
select 'result', case when dt = 2014 then result end
) c (old_col_name, new_col)
) src
pivot
(
count(new_col)
for new_col in([1], [2], [3], [2014], [2013], [2012])
) piv
order by [2014] desc;
See SQL Fiddle with Demo. Then the dynamic sql version would be:
DECLARE #cols AS NVARCHAR(MAX),
#query AS NVARCHAR(MAX),
#orderby nvarchar(max),
#currentYear varchar(4)
select #currentYear = cast(year(getdate()) as varchar(4))
select #cols
= STUFF((SELECT ',' + QUOTENAME(year(date))
from list
group by year(date)
order by year(date) desc
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)')
,1,1,'')
select #orderby = 'ORDER BY ['+ #currentYear + '] desc'
set #query = 'SELECT name, lost = [1],
draw=[2], won = [3],' + #cols + ', Total
from
(
select
name,
new_col,
total
from
(
select name,
dt = year(date),
result,
total = count(*) over(partition by name)
from list
) d
cross apply
(
select ''dt'', dt union all
select ''result'', case when dt = '+#currentYear+' then result end
) c (old_col_name, new_col)
) x
pivot
(
count(new_col)
for new_col in ([1], [2], [3],' + #cols + ')
) p '+ #orderby
exec sp_executesql #query;
See SQL Fiddle with Demo. This version will give a result:
| NAME | LOST | DRAW | WON | 2014 | 2013 | 2012 | TOTAL |
|----------|------|------|-----|------|------|------|-------|
| Person B | 4 | 0 | 2 | 6 | 2 | 2 | 10 |
| Person A | 2 | 1 | 1 | 4 | 3 | 4 | 11 |
| Person C | 1 | 1 | 1 | 3 | 1 | 0 | 4 |

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.
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;
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;
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 |