How to use GROUP BY to concatenate strings in SQL Server?

前端 未结 20 2592
无人及你
无人及你 2020-11-21 04:33

How do I get:

id       Name       Value
1          A          4
1          B          8
2          C          9

to

id               


        
相关标签:
20条回答
  • 2020-11-21 05:00

    If you have clr enabled you could use the Group_Concat library from GitHub

    0 讨论(0)
  • 2020-11-21 05:01

    I ran into a couple of problems when I tried converting Kevin Fairchild's suggestion to work with strings containing spaces and special XML characters (&, <, >) which were encoded.

    The final version of my code (which doesn't answer the original question but may be useful to someone) looks like this:

    CREATE TABLE #YourTable ([ID] INT, [Name] VARCHAR(MAX), [Value] INT)
    
    INSERT INTO #YourTable ([ID],[Name],[Value]) VALUES (1,'Oranges & Lemons',4)
    INSERT INTO #YourTable ([ID],[Name],[Value]) VALUES (1,'1 < 2',8)
    INSERT INTO #YourTable ([ID],[Name],[Value]) VALUES (2,'C',9)
    
    SELECT  [ID],
      STUFF((
        SELECT ', ' + CAST([Name] AS VARCHAR(MAX))
        FROM #YourTable WHERE (ID = Results.ID) 
        FOR XML PATH(''),TYPE 
         /* Use .value to uncomment XML entities e.g. &gt; &lt; etc*/
        ).value('.','VARCHAR(MAX)') 
      ,1,2,'') as NameValues
    FROM    #YourTable Results
    GROUP BY ID
    
    DROP TABLE #YourTable
    

    Rather than using a space as a delimiter and replacing all the spaces with commas, it just pre-pends a comma and space to each value then uses STUFF to remove the first two characters.

    The XML encoding is taken care of automatically by using the TYPE directive.

    0 讨论(0)
  • 2020-11-21 05:01

    SQL Server 2005 and later allow you to create your own custom aggregate functions, including for things like concatenation- see the sample at the bottom of the linked article.

    0 讨论(0)
  • 2020-11-21 05:01

    Don't need a cursor... a while loop is sufficient.

    ------------------------------
    -- Setup
    ------------------------------
    
    DECLARE @Source TABLE
    (
      id int,
      Name varchar(30),
      Value int
    )
    
    DECLARE @Target TABLE
    (
      id int,
      Result varchar(max) 
    )
    
    
    INSERT INTO @Source(id, Name, Value) SELECT 1, 'A', 4
    INSERT INTO @Source(id, Name, Value) SELECT 1, 'B', 8
    INSERT INTO @Source(id, Name, Value) SELECT 2, 'C', 9
    
    
    ------------------------------
    -- Technique
    ------------------------------
    
    INSERT INTO @Target (id)
    SELECT id
    FROM @Source
    GROUP BY id
    
    DECLARE @id int, @Result varchar(max)
    SET @id = (SELECT MIN(id) FROM @Target)
    
    WHILE @id is not null
    BEGIN
      SET @Result = null
    
      SELECT @Result =
        CASE
          WHEN @Result is null
          THEN ''
          ELSE @Result + ', '
        END + s.Name + ':' + convert(varchar(30),s.Value)
      FROM @Source s
      WHERE id = @id
    
      UPDATE @Target
      SET Result = @Result
      WHERE id = @id
    
      SET @id = (SELECT MIN(id) FROM @Target WHERE @id < id)
    END
    
    SELECT *
    FROM @Target
    
    0 讨论(0)
  • 2020-11-21 05:02

    Using Replace Function and FOR JSON PATH

    SELECT T3.DEPT, REPLACE(REPLACE(T3.ENAME,'{"ENAME":"',''),'"}','') AS ENAME_LIST
    FROM (
     SELECT DEPT, (SELECT ENAME AS [ENAME]
            FROM EMPLOYEE T2
            WHERE T2.DEPT=T1.DEPT
            FOR JSON PATH,WITHOUT_ARRAY_WRAPPER) ENAME
        FROM EMPLOYEE T1
        GROUP BY DEPT) T3
    

    For sample data and more ways click here

    0 讨论(0)
  • 2020-11-21 05:03

    This is just an addition to Kevin Fairchild's post (very clever by the way). I would have added it as a comment, but I don't have enough points yet :)

    I was using this idea for a view I was working on, however the items I was concatinating contained spaces. So I modified the code slightly to not use spaces as delimiters.

    Again thanks for the cool workaround Kevin!

    CREATE TABLE #YourTable ( [ID] INT, [Name] CHAR(1), [Value] INT ) 
    
    INSERT INTO #YourTable ([ID], [Name], [Value]) VALUES (1, 'A', 4) 
    INSERT INTO #YourTable ([ID], [Name], [Value]) VALUES (1, 'B', 8) 
    INSERT INTO #YourTable ([ID], [Name], [Value]) VALUES (2, 'C', 9) 
    
    SELECT [ID], 
           REPLACE(REPLACE(REPLACE(
                              (SELECT [Name] + ':' + CAST([Value] AS VARCHAR(MAX)) as A 
                               FROM   #YourTable 
                               WHERE  ( ID = Results.ID ) 
                               FOR XML PATH (''))
                            , '</A><A>', ', ')
                    ,'<A>','')
            ,'</A>','') AS NameValues 
    FROM   #YourTable Results 
    GROUP  BY ID 
    
    DROP TABLE #YourTable 
    
    0 讨论(0)
提交回复
热议问题