141

I know that in sql server we cannot use Group_concat function but here is one issue i have in which i need to Group_Concat my query.I google it found some logic but not able to correct it.My sql query is

select  m.maskid,m.maskname,m.schoolid,s.schoolname,
md.maskdetail
from tblmask m join school s on s.id = m.schoolid 
join maskdetails md on m.maskid = md.maskid
order by m.maskname ;

It gives me result like

enter image description here

Just look first 3 rows In that maskid,maskname,schoolid,schoolname is same but maskdetail is different so want to one row for that in which last column can contain all maskdetails as per maskid and so on.

I want my output like

enter image description here

And so on. So please help me while making a query for that.

1
  • 23
    This isn't quite a duplicate of the question about SQL Server 2005 since the addition of STRING_AGG to SQL Server 2017, so you might want to look into that if you're blessed with a recent SQL Server. Commented Sep 27, 2017 at 9:12

4 Answers 4

194

Query:

SELECT
      m.maskid
    , m.maskname
    , m.schoolid
    , s.schoolname
    , maskdetail = STUFF((
          SELECT ',' + md.maskdetail
          FROM dbo.maskdetails md
          WHERE m.maskid = md.maskid
          FOR XML PATH(''), TYPE).value('.', 'NVARCHAR(MAX)'), 1, 1, '')
FROM dbo.tblmask m
JOIN dbo.school s ON s.ID = m.schoolid
ORDER BY m.maskname

Additional information:

String Aggregation in the World of SQL Server

Sign up to request clarification or add additional context in comments.

4 Comments

hmmm can you explain @Devart i mean the inner join give result like in image...so to combine in all duplicate m.maskid , m.maskname , m.schoolid , s.schoolname to one row we need group by
Relation between tblmask - maskdetails = 1 to many, so duplicates of records should not be here.
What's the reason for using PATH(''), TYPE and .value('.', 'NVARCHAR(MAX)') here, as opposed to simple PATH('') as in @AmitSingh's asnwer? Your variant yields a way, way heavier execution plan, does it have some hidden advantage to justify the cost? If not, would you correct or amend your answer since it's accepted and is supposed to be the best one?
Ok, I got it. Amit Singh's answer will return the string XML-encoded (because the result of for xml select is an XML text/object), so, for example, < will turn into &gt;. Whereas your answer will return the string verbatim, because value() processes the XML object and extracts the text contents from there.
35
Select
      A.maskid
    , A.maskname
    , A.schoolid
    , B.schoolname
    , STUFF((
          SELECT ',' + T.maskdetail
          FROM dbo.maskdetails T
          WHERE A.maskid = T.maskid
          FOR XML PATH('')), 1, 1, '') as maskdetail 
FROM dbo.tblmask A
JOIN dbo.school B ON B.ID = A.schoolid
Group by  A.maskid
    , A.maskname
    , A.schoolid
    , B.schoolname

1 Comment

+1. By the way GROUP BY not needed here.
9

This can also be achieved using the Scalar-Valued Function in MSSQL 2008
Declare your function as following,

CREATE FUNCTION [dbo].[FunctionName]
(@MaskId INT)
RETURNS Varchar(500) 
AS
BEGIN

    DECLARE @SchoolName varchar(500)                        

    SELECT @SchoolName =ISNULL(@SchoolName ,'')+ MD.maskdetail +', ' 
    FROM maskdetails MD WITH (NOLOCK)       
    AND MD.MaskId=@MaskId

    RETURN @SchoolName

END

And then your final query will be like

SELECT m.maskid,m.maskname,m.schoolid,s.schoolname,
(SELECT [dbo].[FunctionName](m.maskid)) 'maskdetail'
FROM tblmask m JOIN school s on s.id = m.schoolid 
ORDER BY m.maskname ;

Note: You may have to change the function, as I don't know the complete table structure.

4 Comments

Works for me in SQL Server 2012.
Never worked for anyone except by chance. It's undocumented and known to fail since the early 2000s when this first appeared. It's also a lot slower than any other method, up to 20 times compared to FOR XML
NOLOCK makes things a lot worse, as it can return duplicate rows
7

Please run the below query, it doesn't requires STUFF and GROUP BY in your case:

Select
      A.maskid
    , A.maskname
    , A.schoolid
    , B.schoolname
    , CAST((
          SELECT  T.maskdetail+','
          FROM dbo.maskdetails T
          WHERE A.maskid = T.maskid
          FOR XML PATH(''))as varchar(max)) as maskdetail 
FROM dbo.tblmask A
JOIN dbo.school B ON B.ID = A.schoolid

1 Comment

STUFF is required for strip the first comma, in your case maskdetail ends with a comma

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.