Concatenate strings from multiple columns and multiple rows - sql

How to concatenate the strings from multiple rows and multiple columns in SQL Server.
My table is like this:
ItemId AttributeName AttributeValue
---------- ------------- --------------
1 Website www.abc.com
1 Github github.com/abc
1 Facebook facebook.com/abc
2 Website www.123.com
2 Instagram instagram.com/123
and the desired output is:
ItemId Weblinks
---------- -------------
1 Website: www.abc.com; Github: github.com/abc; Facebook: facebook.com/abc
2 Website: www.123.com; Instagram: instagram.com/123
I read from other similar questions that XML PATH is probably required. Please could anyone guide me how to achieve this?

This can also be done with a 2 step query:
SELECT t.id, STRING_AGG(t.sites, ' ') as Weblinks
FROM (
SELECT id, CONCAT(attrName, ': ', attrValue, ';') as sites
FROM test
) as t
GROUP BY t.id
ORDER BY t.id;
The inner concatenates attribute value and name in the desired format, while the outer aggregates the results per user id. Coming from MySQL I find that simpler for some reason.
Demo: here
UPDATE: based on #Panagiotis comment
SELECT t.id, STRING_AGG(CONCAT(t.attrName, ': ', t.attrValue, ';'), ' ') as Weblinks
FROM test t
GROUP BY t.id
ORDER BY t.id;
Demo 2: here

You can use FOR XML PATH() :
SELECT DISTINCT T.ItemId, STUFF(Weblinks, 1, 1, '') AS Weblinks
FROM table T CROSS APPLY
( SELECT CONCAT(';', T1.AttributeName, ':', T1.AttributeValue)
FROM table T1
WHERE T1.ITEMID = T.ITEMID
FOR XML PATH('')
) T1(Weblinks);

Related

Create comma separated group list from rows

I need to extract a comma separated list from the following:
Return should gives something like
1 : Route#1, Route#2
2 : Route#3, Route#4
3 : Route#5
4 : Route#6
I'm struggling with the STUFF function. So far I have:SELECT STUFF( (SELECT DISTINCT ';' + T4.[Outbound Trucks] FROM #TEMP4 T4 FOR XML PATH('') ),1,1,'') AS MasterRoutes
Result gives me
any help would be really appreciated.
thanks a lof for your time
If your sql server is 2017 or more :
SELECT dorno, STRING_AGG ([Outbound Trucks], ',') as CSV
FROM #TEMP4
GROUP BY dorno
Explanation Here
In you case you can eliminate doublon to like this:
with tmp as (
select distinct dorno, [Outbound Trucks] Truck from #TEMP4
)
SELECT dorno, STRING_AGG (Truck, ',') as CSV
FROM tmp
GROUP BY dorno

Using Stuff to roll up data from multiple rows AND concatenate columns

I've found similar questions on the site, but I'm still struggling with this. I have a table with information like the below:
AcctNo ChargeOrder ChargeCode
ABC 1 Charge1
ABC 2 Charge2
ABC 3 Charge3
I'm trying to use the XML Path/STUFF functions to return the data like so:
AcctNo Order/Code
ABC 1:Charge1 - 2:Charge2 - 3:Charge3
But I can't seem to figure out how to concatenate my chargeorder and chargecode AND STUFF them into a single field.
In SQL Server, you can use string_agg() -- in the more recent versions:
select acctno,
string_agg(concat(ChargeOrder, ':', ChargeCode), ' - ')
from t
group by acctno;
In older versions, this would be phrased as:
select a.acctno,
stuff( (select concat(' - ', ChargeOrder, ':', ChargeCode)
from t t2
where t2.acctno = a.acctno
for xml path ('')
), 1, 3, ''
)
from (select distinct acctno from t) a

How to combine return results of query in one row

I have a table that save personnel code.
When I select from this table I get 3 rows result such as:
2129,3394,3508,3534
2129,3508
4056
I want when create select result combine in one row such as:
2129,3394,3508,3534,2129,3508,4056
or distinct value such as:
2129,3394,3508,3534,4056
You should ideally avoid storing CSV data at all in your tables. That being said, for your first result set we can try using STRING_AGG:
SELECT STRING_AGG(col, ',') AS output
FROM yourTable;
Your second requirement is more tricky, and we can try going through a table to remove duplicates:
WITH cte AS (
SELECT DISTINCT VALUE AS col
FROM yourTable t
CROSS APPLY STRING_SPLIT(t.col, ',')
)
SELECT STRING_AGG(col, ',') WITHIN GROUP (ORDER BY CAST(col AS INT)) AS output
FROM cte;
Demo
I solved this by using STUFF and FOR XML PATH:
SELECT
STUFF((SELECT ',' + US.remain_uncompleted
FROM Table_request US
WHERE exclusive = 0 AND reqact = 1 AND reqend = 0
FOR XML PATH('')), 1, 1, '')
Thank you Tim

SQL Concatenate and group

I need a TSQL version of group_concat
Simmilar to the example found here:
Policy Destination ID
-------------------------
PolA DestA 1
PolA DestA 2
PolB DestB 3
PolB DestB 4
PolC DestC 5
PolC DestC 6
PolC DestD 7
The output should look like this:
PolA DestA 1,2
PolB DestB 3,4
PolC DestC 5,6
PolC DestD 7
The grouping is on the uniqueness of both the first 2 columns, and then a concatenated output on the third.
I found this link but it only take into account 2 columns
Any help would be appreciated.
You can try this :
SELECT G.Policy, G.Destination,
stuff(
(select cast(',' as varchar(max)) + U.ID
from yourtable U
WHERE U.Policy = G.Policy and U.Destination = G.Destination
order by U.Policy
for xml path('')
), 1, 1, '') AS IDs
FROM yourtable G group BY G.Policy, G.Destination
In MSSQL Synax:
SELECT Policy, Destination, STRING_AGG ( [ID], ',' ) IDs
FROM Table
I just create the PolA example table for you, just replace the CTE as your table, try below:
WITH ABC
as
(
select 'PolA' as Policy,'DestA' as Destination,'1' as ID
UNION ALL
select 'PolA','DestA','2'
)
SELECT Policy, Destination,
STUFF((SELECT ',' + A.ID FROM ABC as A WHERE A.Policy = B.Policy FOR XML PATH('')),1,1,'') as ID
FROM ABC as B
GROUP BY B.policy, B.Destination

SQL: Pivoting on more than one column

I have a table
Name | Period | Value1 | Value2
-----+---------+---------+-------
A 1 2 3
A 2 5 4
A 3 6 7
B 1 2 3
B 2 5 4
B 3 6 7
I need results like
Name | Value1 | Value2
-----+--------+------
A | 2,5,6 | 3,4,7
B | 2,5,6 | 3,4,7
Number of periods is dynamic but I know how to handle it so, for simplicity, let's say there are 3 periods
The query below gives me results for Value1. How can I get results for both?
I can always do them separately and then do a join but the table is really big and I need "combine" four values, not two. Can I do it in one statement?
SELECT Name,
[1]+','+ [2] + ','+ [3] ValueString
FROM (
select Name, period, cpr from #MyTable
) as s
PIVOT(SUM(Value1)
FOR period IN ([1],[2],[3])
Use conditional aggregation. Combining the values into strings is a bit tricky, requiring XML logic in SQL Server:
select n.name,
stuff((select ',' + cast(value1 as varchar(max))
from t
where n.name = t.name
order by t.period
for xml path ('')
), 1, 1, ''
) as values1,
stuff((select ',' + cast(value2 as varchar(max))
from t
where n.name = t.name
order by t.period
for xml path ('')
), 1, 1, ''
) as values2
from (select distinct name
from t
) n;
Your values look like numbers, hence the explicit cast and the lack of concern for XML special characters.
You may ask why this does the distinct in a subquery rather than in the outer query. If done in the outer query, then the SQL engine will probably do the aggregation for every row before doing the distinct. I'm not sure if the optimizer is good enough run the subqueries only once per name.
Using Group By with stuff function and get expected result
SELECT Name , STUFF((SELECT ',' + CAST(Value1 AS VARCHAR) FROM #MyTable T2 WHERE T1.Name = T2.Name FOR XML PATH('')),1,1,'') Value1
, STUFF((SELECT ',' + CAST(Value2 AS VARCHAR) FROM #MyTable T3 WHERE T1.Name = T3.Name FOR XML PATH('')),1,1,'') Value2 FROM #MyTable T1 GROUP BY Name