Optimal way to concatenate/aggregate strings

前端 未结 7 1302
[愿得一人]
[愿得一人] 2020-11-22 11:17

I\'m finding a way to aggregate strings from different rows into a single row. I\'m looking to do this in many different places, so having a function to facilitate this woul

7条回答
  •  迷失自我
    2020-11-22 11:54

    Although @serge answer is correct but i compared time consumption of his way against xmlpath and i found the xmlpath is so faster. I'll write the compare code and you can check it by yourself. This is @serge way:

    DECLARE @startTime datetime2;
    DECLARE @endTime datetime2;
    DECLARE @counter INT;
    SET @counter = 1;
    
    set nocount on;
    
    declare @YourTable table (ID int, Name nvarchar(50))
    
    WHILE @counter < 1000
    BEGIN
        insert into @YourTable VALUES (ROUND(@counter/10,0), CONVERT(NVARCHAR(50), @counter) + 'CC')
        SET @counter = @counter + 1;
    END
    
    SET @startTime = GETDATE()
    
    ;WITH Partitioned AS
    (
        SELECT 
            ID,
            Name,
            ROW_NUMBER() OVER (PARTITION BY ID ORDER BY Name) AS NameNumber,
            COUNT(*) OVER (PARTITION BY ID) AS NameCount
        FROM @YourTable
    ),
    Concatenated AS
    (
        SELECT ID, CAST(Name AS nvarchar) AS FullName, Name, NameNumber, NameCount FROM Partitioned WHERE NameNumber = 1
    
        UNION ALL
    
        SELECT 
            P.ID, CAST(C.FullName + ', ' + P.Name AS nvarchar), P.Name, P.NameNumber, P.NameCount
        FROM Partitioned AS P
            INNER JOIN Concatenated AS C ON P.ID = C.ID AND P.NameNumber = C.NameNumber + 1
    )
    SELECT 
        ID,
        FullName
    FROM Concatenated
    WHERE NameNumber = NameCount
    
    SET @endTime = GETDATE();
    
    SELECT DATEDIFF(millisecond,@startTime, @endTime)
    --Take about 54 milliseconds
    

    And this is xmlpath way:

    DECLARE @startTime datetime2;
    DECLARE @endTime datetime2;
    DECLARE @counter INT;
    SET @counter = 1;
    
    set nocount on;
    
    declare @YourTable table (RowID int, HeaderValue int, ChildValue varchar(5))
    
    WHILE @counter < 1000
    BEGIN
        insert into @YourTable VALUES (@counter, ROUND(@counter/10,0), CONVERT(NVARCHAR(50), @counter) + 'CC')
        SET @counter = @counter + 1;
    END
    
    SET @startTime = GETDATE();
    
    set nocount off
    SELECT
        t1.HeaderValue
            ,STUFF(
                       (SELECT
                            ', ' + t2.ChildValue
                            FROM @YourTable t2
                            WHERE t1.HeaderValue=t2.HeaderValue
                            ORDER BY t2.ChildValue
                            FOR XML PATH(''), TYPE
                       ).value('.','varchar(max)')
                       ,1,2, ''
                  ) AS ChildValues
        FROM @YourTable t1
        GROUP BY t1.HeaderValue
    
    SET @endTime = GETDATE();
    
    SELECT DATEDIFF(millisecond,@startTime, @endTime)
    --Take about 4 milliseconds
    

提交回复
热议问题