Je trouve un moyen d'agréger des chaînes de différentes lignes en une seule ligne. Je cherche à faire cela dans de nombreux endroits différents, donc avoir une fonction pour faciliter ce serait bien. J'ai essayé des solutions utilisant COALESCE
et FOR XML
, mais elles ne me conviennent pas.
L'agrégation de chaînes ferait quelque chose comme ceci:
id | Name Result: id | Names
-- - ---- -- - -----
1 | Matt 1 | Matt, Rocks
1 | Rocks 2 | Stylus
2 | Stylus
J'ai examiné les fonctions d'agrégation définies par CLR en remplacement de COALESCE
et FOR XML
, mais apparemment, SQL Azure ne prend pas en charge les éléments définis par CLR, ce qui est pénible pour moi car je sais que pouvoir l'utiliser résoudrait beaucoup de problèmes. problèmes pour moi.
Existe-t-il une solution de contournement possible, ou une méthode similaire optimale (qui n'est peut-être pas aussi optimale que CLR, mais bon je vais prendre ce que je peux obtenir) que je peux utiliser pour agréger mes données?
for xml
fonctionne pas pour vous?for xml
montre une utilisation de 25% en termes de performances de requête (une grande partie de la requête!)for xml path
requête. Certains plus rapides que d'autres. Cela pourrait dépendre de vos données, mais celles qui utilisentdistinct
sont, selon mon expérience, plus lentes que celles utiliséesgroup by
. Et si vous utilisez.value('.', nvarchar(max))
pour obtenir les valeurs concaténées, vous devriez changer cela en.value('./text()[1]', nvarchar(max))
Réponses:
SOLUTION
La définition de l' optimal peut varier, mais voici comment concaténer des chaînes de différentes lignes à l'aide de Transact SQL standard, ce qui devrait fonctionner correctement dans Azure.
EXPLICATION
L'approche se résume à trois étapes:
Numéroter les lignes à l' aide
OVER
et dePARTITION
regroupement et leur ordonnant au besoin pour la concaténation. Le résultat estPartitioned
CTE. Nous conservons le nombre de lignes dans chaque partition pour filtrer les résultats ultérieurement.L'utilisation récursive de CTE (
Concatenated
) permet de parcourir les numéros de ligne (NameNumber
colonne) en ajoutant desName
valeurs à laFullName
colonne.Filtrez tous les résultats, sauf ceux avec les plus élevés
NameNumber
.Veuillez garder à l'esprit que pour rendre cette requête prévisible, il faut définir à la fois le regroupement (par exemple, dans votre scénario, les lignes avec les mêmes
ID
sont concaténées) et le tri (j'ai supposé que vous triiez simplement la chaîne par ordre alphabétique avant la concaténation).J'ai rapidement testé la solution sur SQL Server 2012 avec les données suivantes:
Le résultat de la requête:
la source
Les méthodes utilisant FOR XML PATH comme ci-dessous sont-elles vraiment aussi lentes? Itzik Ben-Gan écrit que cette méthode a de bonnes performances dans son livre T-SQL Querying (M. Ben-Gan est une source digne de confiance, à mon avis).
la source
id
colonne une fois que la taille d'une table devient un problème.&
basculé vers&
, etc.). Unefor xml
solution plus correcte est fournie ici .Pour ceux d'entre nous qui ont trouvé ça
et n'utilisez pas Azure SQL Database:STRING_AGG()
dans PostgreSQL, SQL Server 2017 et Azure SQLhttps://www.postgresql.org/docs/current/static/functions-aggregate.html
https://docs.microsoft.com/en-us/sql/t-sql/ fonctions / string-agg-transact-sql
GROUP_CONCAT()
dans MySQLhttp://dev.mysql.com/doc/refman/5.7/en/group-by-functions.html#function_group-concat
(Merci à @Brianjorden et @milanio pour la mise à jour Azure)
Exemple de code:
SQL Fiddle: http://sqlfiddle.com/#!18/89251/1
la source
STRING_AGG
a été repoussé à 2017. Il n'est pas disponible en 2016.Bien que la réponse @serge soit correcte, j'ai comparé la consommation de temps de son chemin à xmlpath et j'ai trouvé que xmlpath était tellement plus rapide. J'écrirai le code de comparaison et vous pourrez le vérifier vous-même. C'est la manière @serge:
Et c'est la manière xmlpath:
la source
Mise à jour: Ms SQL Server 2017+, Azure SQL Database
Vous pouvez utiliser:
STRING_AGG
.L'utilisation est assez simple pour la demande d'OP:
Lire la suite
Eh bien, mon ancienne non-réponse a été supprimée à juste titre (laissée intacte ci-dessous), mais si quelqu'un arrive à atterrir ici à l'avenir, il y a de bonnes nouvelles. Ils ont également implémenté STRING_AGG () dans Azure SQL Database. Cela devrait fournir la fonctionnalité exacte initialement demandée dans cet article avec un support natif et intégré. @hrobky l'a mentionné précédemment en tant que fonctionnalité SQL Server 2016 à l'époque.
--- Old Post: Pas assez de réputation ici pour répondre directement à @hrobky, mais STRING_AGG a l'air génial, mais il n'est actuellement disponible que dans SQL Server 2016 vNext. Espérons que cela suivra bientôt Azure SQL Databse.
la source
STRING_AGG()
est censé devenir disponible dans SQL Server 2017, quel que soit le niveau de compatibilité. docs.microsoft.com/en-us/sql/t-sql/functions/…Vous pouvez utiliser + = pour concaténer des chaînes, par exemple:
si vous sélectionnez @test, il vous donnera tous les noms concaténés
la source
select @test += name + ', ' from names
ORDER BY
dans votre requête. Vous devez utiliser l'une des alternatives répertoriées.J'ai trouvé la réponse de Serge très prometteuse, mais j'ai également rencontré des problèmes de performance avec celle-ci telle qu'elle était écrite. Cependant, lorsque je l'ai restructuré pour utiliser des tables temporaires et ne pas inclure de tables doubles CTE, les performances sont passées de 1 minute 40 secondes à sous-seconde pour 1000 enregistrements combinés. Voici pour tous ceux qui ont besoin de le faire sans FOR XML sur les anciennes versions de SQL Server:
la source