2011-07-05 4 views
20

Supongamos que tengo esta tabla [Tabla1]Cómo concatenar todas las cadenas de una determinada columna para cada grupo

Name Mark 
------- ------ 
ABC  10 
DEF  10 
GHI  10 
JKL  20 
MNO  20 
PQR  30 

¿Cuál debe ser mi instrucción SQL para recuperar un registro que tiene este aspecto: (grupo por [ marca]). he hecho las columnas 1 y 2, pero no saben cómo llevar a cabo la tercera columna (concat [nombre] con el mismo [punto])

mark count  names 
---- -----  ----------- 
10  3  ABC,DEF,GHI 
20  2  JKL,MNO 
30  1  PQR 

estoy usando Microsoft SQL. Por favor ayuda. Gracias

+0

¿Qué DBMS está utilizando? –

+0

Microsoft SQL. Perdón por no haber incluido esta información – yonan2236

+0

Véase también http://stackoverflow.com/questions/451415/simulating-group-concat-mysql-function-in-ms-sql-server-2005 –

Respuesta

35

Si MS SQL 2005 o superior.

declare @t table([name] varchar(max), mark int) 

insert @t values ('ABC', 10), ('DEF', 10), ('GHI', 10), 
    ('JKL', 20), ('MNO', 20), ('PQR', 30) 


select t.mark, COUNT(*) [count] 
    ,STUFF((
     select ',' + [name] 
     from @t t1 
     where t1.mark = t.mark 
     for xml path(''), type 
    ).value('.', 'varchar(max)'), 1, 1, '') [values] 
from @t t 
group by t.mark 

Salida:

mark  count  values 
----------- ----------- -------------- 
10   3   ABC,DEF,GHI 
20   2   JKL,MNO 
30   1   PQR 
+1

+1 for for xml path ('') – Pankaj

+0

¿No hace la diferencia cuando no escribe [valores]? – Pankaj

+0

@SQL, es solo un alias, así que no importa –

1

solución polishchuks es más elegante, pero esto es básicamente la misma cosa, sólo ocupamos de la coma adicional diferente.

CREATE TABLE #Marks(Name nchar(3), Mark int) 

INSERT INTO #Marks 

SELECT 'ABC', 10 UNION ALL 
SELECT 'DEF', 10 UNION ALL 
SELECT 'GHI', 10 UNION ALL 
SELECT 'JKL', 20 UNION ALL 
SELECT 'MNO', 20 UNION ALL 
SELECT 'PQR', 30 


SELECT 
    mark, 
    [count], 
    CASE WHEN Len(Names) > 0 THEN LEFT(Names, LEN(Names) -1) ELSE '' END names 
    FROM 
(
SELECT 
    Mark, 
    COUNT(Mark) AS [count], 
     (
     SELECT DISTINCT 
      Name + ', ' 
     FROM 
      #Marks M1 
     WHERE M1.Mark = M2.Mark 
     FOR XML PATH('')  
     ) Names 
FROM #Marks M2 
GROUP BY Mark 
) M 
+0

No estoy seguro si necesita la primera cláusula distinta en la primera subconsulta cuando está haciendo un grupo por marca, corríjanme si estoy equivocado ... – Ram

+0

sí, no lo necesitaría – woggles

4

Aquí hay una respuesta relacionada con el rendimiento.

http://jerrytech.blogspot.com/2010/04/tsql-concatenate-strings-1-2-3-and.html

Uso de las funciones XML en una consulta de gran tamaño es un asesino rendimiento.

El uso de un CTE es una superestrella del rendimiento.

Echa un vistazo al enlace, se explicará cómo.

Admito que el trabajo para lograrlo es más.

Pero el resultado es milisegundos en millones de filas.

0

Basado libremente en Itzik Ben-Gan, Dentro de Microsoft SQL Server 2005: Programación de T-SQL, p. 215:

IF OBJECT_ID('dbo.Table1') IS NOT NULL 
    DROP TABLE dbo.Table1 ; 
GO 
CREATE TABLE dbo.Table1 (Name VARCHAR(10), Mark INT) ; 

INSERT INTO dbo.Table1 (Name, Mark) VALUES ('ABC',  10) ; 
INSERT INTO dbo.Table1 (Name, Mark) VALUES ('DEF',  10) ; 
INSERT INTO dbo.Table1 (Name, Mark) VALUES ('GHI',  10) ; 
INSERT INTO dbo.Table1 (Name, Mark) VALUES ('JKL',  20) ; 
INSERT INTO dbo.Table1 (Name, Mark) VALUES ('MNO',  20) ; 
INSERT INTO dbo.Table1 (Name, Mark) VALUES ('PQR',  30) ; 


WITH DelimitedNames AS 
(
    SELECT Mark, T2.Count, 
     ( SELECT Name + ',' AS [text()] 
      FROM dbo.Table1 AS T1 
      WHERE T1.Mark = T2.Mark 
      ORDER BY T1.Mark 
      FOR XML PATH('')) AS Names 
    FROM (SELECT Mark, COUNT(*) AS Count FROM dbo.Table1 GROUP BY Mark) AS T2 
) 
SELECT Mark, Count, LEFT(Names, LEN(NAMES) - 1) AS Names 
FROM DelimitedNames ; 
Cuestiones relacionadas