2009-06-02 18 views
10

Si tengo una tabla como la siguiente:grupos ConCat en SQL Server

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

¿Cómo puedo obtener un conjunto de resultados como esto:

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

Sé que esto es muy fácil de hacer en MySQL utilizando GROUP_CONCAT, pero tengo que ser capaz de hacerlo en MSSQL 2005

Gracias

(duplicado de 01.237.)

Respuesta

10

Para una solución limpia y eficiente puede crear an user defined aggregate function, incluso hay an example que hace precisamente lo que necesita.
entonces Se puede utilizar como cualquier otra función de agregado (con un plan de consulta estándar):

query plan

+0

la solución más limpia hasta ahora – Spyros

2

menudo asked here.

La forma más eficiente es utilizar el truco FOR XML PATH.

5

Esto va a hacer:

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

Este concats los valores en un documento XML, lo cual es indeseable. – Boog

+4

No, usa funciones XML. No hay documentos XML involucrados. ¿Por qué es "indeseable"? –

1

Esto acaba de llegar a mí como una posible solución. No tengo idea de rendimiento, pero pensé que sería una forma interesante de resolver el problema. Probé que funciona en una situación simple (no codifiqué para dar cuenta de NULL). Siéntete libre de probarlo para ver si te funciona bien.

La tabla que utilicé incluía una identificación (my_id). Eso realmente podría ser cualquier columna que sea única dentro del grupo (grp_id), por lo que podría ser una columna de fecha o lo que sea.

;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