Estoy encontrando una manera de agregar cadenas de diferentes filas en una sola fila. Estoy buscando hacer esto en muchos lugares diferentes, por lo que sería bueno tener una función para facilitar esto. He probado soluciones usando COALESCE
y FOR XML
, pero simplemente no me sirven.
La agregación de cadenas haría algo como esto:
id | Name Result: id | Names
-- - ---- -- - -----
1 | Matt 1 | Matt, Rocks
1 | Rocks 2 | Stylus
2 | Stylus
He echado un vistazo a las funciones agregadas definidas por CLR como reemplazo de COALESCE
y FOR XML
, pero aparentemente SQL Azure no es compatible con cosas definidas por CLR, lo cual es una molestia para mí porque sé que poder usarlo resolvería una gran cantidad de problemas para mi.
¿Existe alguna solución alternativa o un método igualmente óptimo (que podría no ser tan óptimo como CLR, pero bueno , tomaré lo que pueda obtener) que pueda usar para agregar mis cosas?
for xml
te funciona?for xml
muestra un uso del 25% en términos de rendimiento de la consulta (¡la mayor parte de la consulta!)for xml path
consulta. Algunos más rápidos que otros. Podría depender de sus datos, pero los que usandistinct
son, en mi experiencia, más lentos que los que usangroup by
. Y si está utilizando.value('.', nvarchar(max))
para obtener los valores concatenados, debe cambiar eso a.value('./text()[1]', nvarchar(max))
Respuestas:
SOLUCIÓN
La definición de óptimo puede variar, pero aquí se explica cómo concatenar cadenas de diferentes filas mediante Transact SQL normal, que debería funcionar bien en Azure.
EXPLICACIÓN
El enfoque se reduce a tres pasos:
Numere las filas usando
OVER
yPARTITION
agrupando y ordenándolas según sea necesario para la concatenación. El resultado esPartitioned
CTE. Mantenemos recuentos de filas en cada partición para filtrar los resultados más tarde.Usando CTE recursivo (
Concatenated
) iterar a través de los números de fila (NameNumber
columna) agregandoName
valores a laFullName
columna.Filtra todos los resultados excepto los que tengan los más altos
NameNumber
.Tenga en cuenta que para que esta consulta sea predecible, uno debe definir tanto la agrupación (por ejemplo, en su escenario, las filas con lo mismo
ID
están concatenados) como la ordenación (asumí que simplemente ordenó la cadena alfabéticamente antes de la concatenación).Probé rápidamente la solución en SQL Server 2012 con los siguientes datos:
El resultado de la consulta:
fuente
¿Son los métodos que usan FOR XML PATH como a continuación realmente tan lentos? Itzik Ben-Gan escribe que este método tiene un buen rendimiento en su libro T-SQL Querying (el Sr. Ben-Gan es una fuente confiable, en mi opinión).
fuente
id
columna una vez que el tamaño de la tabla se convierta en un problema.&
cambiado a&
, y así sucesivamente). Aquífor xml
se proporciona una solución más correcta .Para aquellos de nosotros que encontramos esto
y no están usando Azure SQL Database:STRING_AGG()
en PostgreSQL, SQL Server 2017 y Azure SQLhttps://www.postgresql.org/docs/current/static/functions-aggregate.html
https://docs.microsoft.com/en-us/sql/t-sql/ funciones / string-agg-transact-sql
GROUP_CONCAT()
en MySQLhttp://dev.mysql.com/doc/refman/5.7/en/group-by-functions.html#function_group-concat
(Gracias a @Brianjorden y @milanio por la actualización de Azure)
Código de ejemplo:
Violín SQL: http://sqlfiddle.com/#!18/89251/1
fuente
STRING_AGG
se retrasó a 2017. No está disponible en 2016.Aunque la respuesta de @serge es correcta, comparé el consumo de tiempo de su camino con xmlpath y descubrí que xmlpath es mucho más rápido. Escribiré el código de comparación y podrás comprobarlo tú mismo. Esta es la forma @serge:
Y esta es la forma xmlpath:
fuente
Actualización: MS SQL Server 2017+, Azure SQL Database
Se puede utilizar:
STRING_AGG
.El uso es bastante simple para la solicitud de OP:
Lee mas
Bueno, mi anterior no respuesta se eliminó legítimamente (se dejó intacta a continuación), pero si alguien aterriza aquí en el futuro, hay buenas noticias. También han implementado STRING_AGG () en Azure SQL Database. Eso debería proporcionar la funcionalidad exacta originalmente solicitada en esta publicación con soporte nativo e integrado. @hrobky mencionó esto anteriormente como una característica de SQL Server 2016 en ese momento.
--- Publicación anterior: No hay suficiente reputación aquí para responder a @hrobky directamente, pero STRING_AGG se ve muy bien, sin embargo, solo está disponible en SQL Server 2016 vNext actualmente. Con suerte, también seguirá pronto a Azure SQL Datababse.
fuente
STRING_AGG()
se afirma que estará disponible en SQL Server 2017, en cualquier nivel de compatibilidad. docs.microsoft.com/en-us/sql/t-sql/functions/...Puede usar + = para concatenar cadenas, por ejemplo:
si selecciona @test, le dará todos los nombres concatenados
fuente
select @test += name + ', ' from names
ORDER BY
en su consulta. Debe utilizar una de las alternativas enumeradas.Encontré la respuesta de Serge muy prometedora, pero también encontré problemas de rendimiento con ella tal como estaba escrita. Sin embargo, cuando lo reestructuré para usar tablas temporales y no incluir tablas de CTE dobles, el rendimiento pasó de 1 minuto y 40 segundos a menos de un segundo para 1000 registros combinados. Aquí está para cualquiera que necesite hacer esto sin FOR XML en versiones anteriores de SQL Server:
fuente