Merge column value based on another column value - TSQL - sql

I m using the below query to merge column Message based on column 'Customer_Name' from table Customers
SELECT
[Customer_Name],
STUFF((SELECT
', ' + LTRIM(RTRIM([Message]))
FROM [dbo].[Customers] t2
WHERE t2.[Customer_Name] = t1.[Customer_Name]
FOR XML PATH ('')), 1, 1, '')
FROM [dbo].[Customers] t1
GROUP BY [Customer_Name]
Using the above code, the Message are separated by , but i want a new line. i try to use CHAR(13)+CHAR(10) but i getting #x0D; and the merge column seems to be wrong.
Any idea on how to fix it will greatly appreciate.
Answer using #Larnu help and posts on comments
SELECT
[Customer_Name],
STUFF((SELECT
(CHAR(13) + CHAR(10)) + LTRIM(RTRIM([Message]))
FROM [Customers] t2
WHERE t2.[Customer_Name] = t1.[Customer_Name]
FOR XML PATH (''),TYPE
).value('(./text())[1]','varchar(MAX)'),1,2,'')
FROM [Customers] t1
GROUP BY [Customer_Name]

Your solution use xml serialization .
#x0D; is xml serialization of char(13)
If you use at least SQL Server 2017 you can use STRING_AGG function
SELECT
[Customer_Name],
STRING_AGG([Message],', ') as [Messages]
FROM [dbo].[Customers] t1
GROUP BY [Customer_Name]
otherwise you can add replace.
SELECT
[Customer_Name],
REPLACE(
STUFF((SELECT
', ' + LTRIM(RTRIM([Message]))
FROM [dbo].[Customers] t2
WHERE t2.[Customer_Name] = t1.[Customer_Name]
FOR XML PATH ('')), 1, 2, ''),
'#x0D;',
CHAR(13)) as [Messages]
FROM [dbo].[Customers] t1
GROUP BY [Customer_Name]

The correct method to prevent XML entitization is actually to generate it as the xml data type using the TYPE option, then pull it back out with .value
DECLARE #sep NVARCHAR(10) = ', '; -- or you can use CHAR(13)+CHAR(10)
SELECT
[Customer_Name],
STUFF(
(SELECT #sep + LTRIM(RTRIM([Message]))
FROM [dbo].[Customers] t2
WHERE t2.[Customer_Name] = t1.[Customer_Name]
FOR XML PATH (''), TYPE
).value('text()[1]','nvarchar(max)'), 1, LEN(#sep), '')
FROM [dbo].[Customers] t1
GROUP BY [Customer_Name]

Related

How to combine string in one column based on grouping

I have a table has data like this
And want to combine the job which has same template in one column, like this
I try to use FOR XML PATH
select t.JBTemplate,
Stuff(
(SELECT N', ' + Contract FROM Table1 FOR XML PATH(''),TYPE)
.value('text()1','nvarchar(max)'),1,2,N'') Job
from Table1 t
group by t.JBTemplate, Contract
However, it combine all job for each template.
Please try this:
IF (OBJECT_ID('tempdb..#my_job_template') IS NOT NULL)
BEGIN
DROP TABLE #my_job_template
END;
CREATE TABLE #my_job_template (JCCO INT NOT NULL, [Contract] nvarchar(max) NULL, [JBTemplate] nvarchar(max) NULL);
INSERT INTO #my_job_template(JCCO, [JBTemplate], [Contract])
VALUES (17, 'Ascend AL', '601226.17')
,(17, '1192-10803', '601236.17')
,(17, 'P66_4Sites', '600948.17')
,(17, 'P66_4Sites', '601219.17')
,(17, 'P66_4Sites', '601234.17')
--select * from #my_job_template
SELECT [JCCO]
, [JBTemplate]
,STUFF((SELECT ', ' + CAST([Contract] AS VARCHAR(MAX)) [text()]
FROM #my_job_template
WHERE [JBTemplate] = t.[JBTemplate]
FOR XML PATH(''), TYPE)
.value('.','NVARCHAR(MAX)'),1,2,' ') [Contract]
FROM #my_job_template t
GROUP BY [JBTemplate] , [JCCO]

Concatenate column values based on type result

Declare #name nvarchar(max),#Id int
SELECT #Id=[EmpType],#name =ISNULL(#name + ',','')+[UserName] FROM [dbo].[TestTable]
Group by [EmpType]
SELECT #Id,#name
Getting error with this code, How can i get the result employee type wise concatenated usernames
Expecting Result set
You can try below using STUFF() function
SELECT [EmpType], abc = STUFF(
(SELECT ',' + [UserName]
FROM [dbo].TestTable] t1
WHERE t1.[EmpType] = t2.[EmpType]
FOR XML PATH (''))
, 1, 1, '') from [dbo].TestTable] t2
group by [EmpType];

MSSQL - GROUP_CONCAT

Here is the sample data :
IdProduit Localisation Qte_EnMain
4266864286880063006 E2-R40-B-T 13.00000
4266864286880063006 E2-R45-B-T 81.00000
4266864286880063007 E2-R45-C-T 17.00000
4266864286880063008 E2-R37-B-T 8.00000
And this is what i would like to have
IdProduit AllLocalisation
4266864286880063006 E2-R40-B-T (13), E2-R45-B-T (81)
4266864286880063007 E2-R45-C-T (17)
4266864286880063008 E2-R37-B-T (8)
I watched all the examples of GROUP_CONCAT on the forum and I tried several tests.
I don't really understand STUFF().
Here is what i would like to do :
SELECT
a.IdProduit,
GROUP_CONCAT(
CONCAT(b.Localisation, ' (', CAST(ROUND(a.Qte_EnMain, 0) AS NUMERIC(36, 0)), ')')
) AS AllLocation
FROM
ogasys.INV_InventENTLoc a
LEFT JOIN ogasys.INV_LocName b ON a.IdLoc = b.IdLoc
GROUP BY a.IdProduit, b.Localisation, a.Qte_EnMain
Now because GROUP_CONCAT is nto working with MSSQL this is the query i have created with all example on this forum.
SELECT
DISTINCT
a1.IdProduit,
STUFF((SELECT DISTINCT '' + b2.Localisation
FROM
ogasys.INV_InventENTLoc a2
LEFT JOIN ogasys.INV_LocName b2 ON a2.IdLoc = b2.IdLoc
WHERE a2.IdLoc = a1.IdLoc
FOR XML PATH(''), TYPE).value('.', 'NVARCHAR(MAX)'), 1, 0, '') data
FROM
ogasys.INV_InventENTLoc a1
LEFT JOIN ogasys.INV_LocName b1 ON a1.IdLoc = b1.IdLoc
ORDER BY a1.IdProduit
The query only return one localisation by row i don't understand how to make this query working.
EDIT:
Here is the solution for my situation :
SELECT
a.IdProduit,
STUFF(
(SELECT ', ' + b2.Localisation + ' (' + CAST(CAST(ROUND(a2.Qte_EnMain, 0) AS NUMERIC(36, 0)) AS VARCHAR(32)) + ')'
FROM ogasys.INV_InventENTLoc a2
LEFT JOIN ogasys.INV_LocName b2 ON a2.IdLoc = b2.IdLoc
WHERE a.IdProduit = a2.IdProduit
FOR XML PATH (''))
, 1, 1, '') AS AllLocalisation
FROM
ogasys.INV_InventENTLoc a
LEFT JOIN ogasys.INV_LocName b ON a.IdLoc = b.IdLoc
GROUP BY a.IdProduit
using STUFF
declare #table table (IdProduit varchar(100), Localisation varchar(50), Qte_EnMain float)
insert into #table
values
('4266864286880063006','E2-R40-B-T', 13.00000),
('4266864286880063006','E2-R45-B-T', 81.00000),
('4266864286880063007','E2-R45-C-T', 17.00000),
('4266864286880063008','E2-R37-B-T', 8.00000)
select IdProduit,
STUFF (
(SELECT
',' + localisation + concat(' (',cast(qte_enMain as varchar(4)),') ')
FROM #table t2
where t2.IdProduit = t1.IdProduit
FOR XML PATH('')), 1, 1, ''
)
from #table t1
group by
IdProduit

SQL - Combine Multiple Columns with Multiple Rows into one row

What I'm trying to do:
I have records in a SQL table where there are 5 columns and thousands of rows.
The rows share duplicate data (i.e. account number) but what makes each unique is that data in one of the columns is different.
As an example:
col1|col2|col3|col4|col5
------------------------
123|abc|456|def|789
123|abc|456|def|date
But the columns can have different values, not necessarily always in column 5.
Here's what I started with:
SELECT TOP (15) stuff((
SELECT ', ' + te.[accountid]
,te.[char1]
,te.[date]
,te.[date2]
,te.[char2]
FROM D AS te
INNER JOIN D AS tue ON tue.[accountid] = te.[accountid]
WHERE tue.[accountid] = ue.[accountid]
FOR XML path('')
,type
).value('.', 'varchar(max)'), 1, 2, '') AS ifile
FROM D AS ue
GROUP BY ue.[accountid]
But I get a monster long string that includes the duplicate rows in one column. I'm not sure what else to try so any insight would be appreciated.
If I had to guess, you have an unnecessary self join in the subquery:
SELECT TOP (15) stuff((
SELECT ', ' + te.[accountid], te.[char1], te.[date], te.[date2], te.[char2]
FROM D te
WHERE te.[accountid] = ue.[accountid]
FOR XML path(''), type
).value('.', 'varchar(max)'), 1, 2, '') AS ifile
FROM D ue
GROUP BY ue.[accountid];
You might also want SELECT DISTINCT in the subquery.
Use UNION to get rid of all the duplicate values and use your FOR XML PATH on the output to append it to a single string:
SELECT TOP (15) stuff((
SELECT ', ' + CAST(te.[accountid] AS varchar(255)) FROM D
UNION
SELECT ', ' + CAST(te.[char1] AS varchar(255)) FROM D
UNION
SELECT ', ' + CAST(te.[date] AS varchar(255)) FROM D
UNION
SELECT ', ' + CAST(te.[date2] AS varchar(255)) FROM D
UNION
SELECT ', ' + CAST(te.[char2] AS varchar(255)) FROM D
FOR XML path('')
,type
).value('.', 'varchar(max)'), 1, 2, '') AS ifile
Untested, treat as pseudo-code to give the general idea.

Convert a row as column and merge two column as its value

I have stuck in a select statement, converting rows into columns. I have tried with PIVOT, i was able to convert the single column. But my requirement is little different. I have explained the requirement below.
I have a table structure as below,
I want to select the data as below,
The values in the table are dynamic, which is not a problem for me to deal with that. But i need a way to get the below result.
Could someone please give me a hint on doing it, may be a way to modify the PIVOT below.
select *
from
(
select TSID,AID,Count,BID
from tbl TS
WHERE TS.TPID = 1
) src
pivot
(
sum(Count)
for AID in (AID1,AID2,AID3)
) piv
Thank you..
You may check this fiddle
EDIT
This will work for not previously known column names
DECLARE #Columns AS VARCHAR(MAX)
DECLARE #SQL AS VARCHAR(MAX)
SELECT #Columns = STUFF(( SELECT DISTINCT ',' + AID
FROM Table1
FOR
XML PATH('')
), 1, 1, '')
SET #SQL = '
;WITH MyCTE AS
(
SELECT TSID,
AID,
STUFF(( SELECT '','' + CONVERT(VARCHAR,[Count] )
FROM Table1 I Where I.TSID = O.TSID
FOR
XML PATH('''')
), 1, 1, '''') AS CountList
FROM Table1 O
GROUP BY TSID,
AID
)
SELECT *
FROM MyCTE
PIVOT
(
MAX(CountList)
FOR AID IN
(
' + #Columns + '
)
) AS PivotTable'
EXEC(#SQL)