2009-06-02 9 views
10

Si j'ai une table comme ceci:groupes concat dans SQL Server

+------------+ 
| Id | Value | 
+------------+ 
| 1 | 'A' | 
|------------| 
| 1 | 'B' | 
|------------| 
| 2 | 'C' | 
+------------+ 

Comment puis-je obtenir un ResultSet comme ceci:

+------------+ 
| Id | Value | 
+------------+ 
| 1 | 'AB' | 
|------------| 
| 2 | 'C' | 
+------------+ 

Je sais que cela est vraiment facile à faire en utilisant MySQL GROUP_CONCAT, mais je dois être en mesure de le faire en MSSQL 2005

Merci

(en double de How to use GROUP BY to concatenate strings in SQL Server?)

Répondre

10

Pour une solution propre et efficace, vous pouvez créer an user defined aggregate function, il y a même an example qui fait exactement ce dont vous avez besoin.
Vous pouvez alors l'utiliser comme toute autre fonction d'agrégation (avec un plan de requête standard):

query plan

+0

la solution la plus propre pour le moment – Spyros

2

Souvent asked here.

Le moyen le plus efficace consiste à utiliser l'astuce FOR XML PATH.

5

Cela fera:

SELECT mt.ID, 
     SUBSTRING((SELECT mt2.Value 
        FROM MyTable AS mt2 
        WHERE mt2.ID = mt.ID 
        ORDER BY mt2.VALUE 
        FOR XML PATH('')), 3, 2000) AS JoinedValue 
FROM MyTable AS mt 
+0

Ce concats les valeurs dans un document XML, ce qui est indésirable. – Boog

+4

Non, il utilise des fonctions XML. Aucun document XML n'est impliqué. Pourquoi est-ce "indésirable"? –

1

Ce vient à moi comme une solution possible. Je n'ai aucune idée de la performance, mais je pensais que ce serait une façon intéressante de résoudre le problème. J'ai testé que cela fonctionne dans une situation simple (je n'ai pas codé pour tenir compte des valeurs NULL). N'hésitez pas à lui faire un test pour voir s'il fonctionne bien pour vous.

La table que j'ai utilisée incluait un identifiant (my_id). Cela pourrait être n'importe quelle colonne qui est unique dans le groupe (grp_id), donc cela pourrait être une colonne de date ou autre.

;WITH CTE AS (
    SELECT 
     T1.my_id, 
     T1.grp_id, 
     CAST(T1.my_str AS VARCHAR) AS my_str 
    FROM 
     dbo.Test_Group_Concat T1 
    WHERE NOT EXISTS (SELECT * FROM dbo.Test_Group_Concat T2 WHERE T2.grp_id = T1.grp_id AND T2.my_id < T1.my_id) 
    UNION ALL 
    SELECT 
     T3.my_id, 
     T3.grp_id, 
     CAST(CTE.my_str + T3.my_str AS VARCHAR) 
    FROM 
     CTE 
    INNER JOIN dbo.Test_Group_Concat T3 ON 
     T3.grp_id = CTE.grp_id AND 
     T3.my_id > CTE.my_id 
    WHERE 
     NOT EXISTS (SELECT * FROM dbo.Test_Group_Concat T4 WHERE 
     T4.grp_id = CTE.grp_id AND 
     T4.my_id > CTE.my_id AND 
     T4.my_id < T3.my_id) 
) 
SELECT 
    CTE.grp_id, 
    CTE.my_str 
FROM 
    CTE 
INNER JOIN (SELECT grp_id, MAX(my_id) AS my_id FROM CTE GROUP BY grp_id) SQ ON 
    SQ.grp_id = CTE.grp_id AND 
    SQ.my_id = CTE.my_id 
ORDER BY 
    CTE.grp_id