Sqlserver
 sql >> Database >  >> RDS >> Sqlserver

Modo ottimale per concatenare/aggregare stringhe

SOLUZIONE

La definizione di ottimale può variare, ma ecco come concatenare stringhe da righe diverse usando il normale Transact SQL, che dovrebbe funzionare correttamente in Azure.

;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 dbo.SourceTable
),
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

SPIEGAZIONE

L'approccio si riduce a tre fasi:

  1. Numera le righe usando OVER e PARTITION raggruppandoli e ordinandoli secondo necessità per la concatenazione. Il risultato è Partitioned CTE. Manteniamo il conteggio delle righe in ogni partizione per filtrare i risultati in un secondo momento.

  2. Utilizzando CTE ricorsivo (Concatenated ) scorrere i numeri di riga (NameNumber colonna) aggiungendo Name valori in FullName colonna.

  3. Filtra tutti i risultati tranne quelli con il NameNumber più alto .

Tieni presente che per rendere prevedibile questa query è necessario definire entrambi i raggruppamenti (ad esempio, nel tuo scenario righe con lo stesso ID sono concatenati) e l'ordinamento (presumo che si ordina semplicemente la stringa in ordine alfabetico prima della concatenazione).

Ho testato rapidamente la soluzione su SQL Server 2012 con i seguenti dati:

INSERT dbo.SourceTable (ID, Name)
VALUES 
(1, 'Matt'),
(1, 'Rocks'),
(2, 'Stylus'),
(3, 'Foo'),
(3, 'Bar'),
(3, 'Baz')

Il risultato della query:

ID          FullName
----------- ------------------------------
2           Stylus
3           Bar, Baz, Foo
1           Matt, Rocks