I'm finding a way to aggregate strings from different rows into a single row. I'm looking to do this in many different places, so having a function to facilitate this would be nice. I've tried solutions using COALESCE
and FOR XML
, but they just don't cut it for me.
String aggregation would do something like this:
id | Name Result: id | Names
-- - ---- -- - -----
1 | Matt 1 | Matt, Rocks
1 | Rocks 2 | Stylus
2 | Stylus
I've taken a look at CLR-defined aggregate functions as a replacement for COALESCE
and FOR XML
, but apparently SQL Azuredoes not support CLR-defined stuff, which is a pain for me because I know being able to use it would solve a whole lot of problems for me.
Is there any possible workaround, or similarly optimal method (which might not be as optimal as CLR, but hey I'll take what I can get) that I can use to aggregate my stuff?
8条答案
按热度按时间olhwl3o21#
SOLUTION
The definition of optimal can vary, but here's how to concatenate strings from different rows using regular Transact SQL, which should work fine in Azure.
EXPLANATION
The approach boils down to three steps:
OVER
andPARTITION
grouping and ordering them as needed for the concatenation. The result isPartitioned
CTE. We keep counts of rows in each partition to filter the results later.Concatenated
) iterate through the row numbers (NameNumber
column) addingName
values toFullName
column.NameNumber
.Please keep in mind that in order to make this query predictable one has to define both grouping (for example, in your scenario rows with the same
ID
are concatenated) and sorting (I assumed that you simply sort the string alphabetically before concatenation).I've quickly tested the solution on SQL Server 2012 with the following data:
The query result:
xxslljrj2#
Are methods using FOR XML PATH like below really that slow? Itzik Ben-Gan writes that this method has good performance in his T-SQL Querying book (Mr. Ben-Gan is a trustworthy source, in my view).
1cklez4t3#
STRING_AGG()
in SQL Server 2017, Azure SQL, and PostgreSQL: https://www.postgresql.org/docs/current/static/functions-aggregate.htmlhttps://learn.microsoft.com/en-us/sql/t-sql/functions/string-agg-transact-sql
GROUP_CONCAT()
in MySQLhttp://dev.mysql.com/doc/refman/5.7/en/group-by-functions.html#function_group-concat
(Thanks to @Brianjorden and @milanio for Azure update)
Example Code:
SQL Fiddle: http://sqlfiddle.com/#!18/89251/1
jaql4c8m4#
Although @serge answer is correct but i compared time consumption of his way against xmlpath and i found the xmlpath is so faster. I'll write the compare code and you can check it by yourself. This is @serge way:
And this is xmlpath way:
o7jaxewo5#
Update: Ms SQL Server 2017+, Azure SQL Database
You can use:
STRING_AGG
.Usage is pretty simple for OP's request:
Read More
Well my old non-answer got rightfully deleted (left in-tact below), but if anyone happens to land here in the future, there is good news. They have implimented STRING_AGG() in Azure SQL Database as well. That should provide the exact functionality originally requested in this post with native and built in support. @hrobky mentioned this previously as a SQL Server 2016 feature at the time.
--- Old Post: Not enough reputation here to reply to @hrobky directly, but STRING_AGG looks great, however it is only available in SQL Server 2016 vNext currently. Hopefully it will follow to Azure SQL Datababse soon as well..
sauutmhj6#
You can use += to concatenate strings, for example:
if you select @test, it will give you all names concatenated
zxlwwiss7#
I found Serge's answer to be very promising, but I also encountered performance issues with it as-written. However, when I restructured it to use temporary tables and not include double CTE tables, the performance went from 1 minute 40 seconds to sub-second for 1000 combined records. Here it is for anyone who needs to do this without FOR XML on older versions of SQL Server:
wvmv3b1j8#
Try this, i use it in my projects