Tema SQL
STRING_AGG() (SQL Server)
Concatena valores por grupo con separador obligatorio (SQL Server 2017+). Equivalente práctico a GROUP_CONCAT() en MySQL; admite WITHIN GROUP (ORDER BY).
Descripción
STRING_AGG ( expresión, separador ) [ WITHIN GROUP ( ORDER BY … ) ] resume filas de un grupo en un VARCHAR/NVARCHAR cuyo tamaño máximo depende del tipo y de la configuración. El separador es obligatorio (a diferencia de algunos usos de GROUP_CONCAT con coma por defecto). WITHIN GROUP permite ordenar los valores antes de concatenar, análogo al ORDER BY interno de GROUP_CONCAT. En SQL Server no existe DISTINCT directo dentro de STRING_AGG: para eliminar duplicados suele usarse una subconsulta o CTE previa con DISTINCT o GROUP BY. Para volúmenes enormes, vigila el límite de 8 KB en VARCHAR o usa NVARCHAR según necesidad Unicode. En PostgreSQL el paralelo es STRING_AGG; en Oracle LISTAGG.
Estructura general
Forma habitual de la sentencia: orden de cláusulas, qué parte filtra, agrupa o proyecta columnas, y qué devuelve el motor. Cópiala como plantilla y sustituye nombres por tus tablas reales.
STRING_AGG(expresión, separador) [ WITHIN GROUP ( ORDER BY orden ) ]
Componentes
Cada componente tiene un papel concreto en la ejecución lógica de la sentencia. Léelos en orden: así entiendes qué puedes omitir, qué es obligatorio y qué expresiones son válidas en cada sitio según tu motor.
- Separador
- Literal o expresión NVARCHAR/VARCHAR entre comillas; define el texto entre valores consecutivos.
- ORDER BY en WITHIN GROUP
- Determina el orden de concatenación dentro de cada grupo del GROUP BY exterior.
- MySQL
- GROUP_CONCAT( col ORDER BY … SEPARATOR … ) ofrece control similar; revisa límites group_concat_max_len.
- NULL
- Los NULL suelen omitirse en la concatenación; comportamiento detallado en documentación de versión.
Ejemplos
Ejemplo 1
SELECT STRING_AGG(nombre, ', ') WITHIN GROUP (ORDER BY nombre)
FROM clientes
WHERE activo = 1;
SELECT d.nombre AS depto,
STRING_AGG(e.nombre, N' | ') WITHIN GROUP (ORDER BY e.apellido)
FROM empleados e
INNER JOIN departamentos d ON d.id = e.depto_id
GROUP BY d.id, d.nombre;
Ejemplo 2
SELECT categoria_id,
STRING_AGG(titulo, N' · ') WITHIN GROUP (ORDER BY titulo)
FROM articulos
GROUP BY categoria_id;
Los ejemplos son ilustrativos. En producción usa consultas parametrizadas (prepared statements), revisa índices y aplica el principio de menor privilegio en cuentas de base de datos.