web-dev-qa-db-fra.com

Requête SQL - Concaténation des résultats en une chaîne

J'ai une fonction SQL qui comprend ce code:

DECLARE @CodeNameString varchar(100)

SELECT CodeName FROM AccountCodes ORDER BY Sort

Je dois concaténer tous les résultats de la requête sélectionnée dans CodeNameString.

Évidemment, une boucle FOREACH en code C # ferait cela, mais comment puis-je le faire en SQL?

30
Matthew Jones

Si vous êtes sur SQL Server 2005 ou supérieur, vous pouvez utiliser cette astuce FOR XML PATH & STUFF:

DECLARE @CodeNameString varchar(100)

SELECT 
   @CodeNameString = STUFF( (SELECT ',' + CodeName 
                             FROM dbo.AccountCodes 
                             ORDER BY Sort
                             FOR XML PATH('')), 
                            1, 1, '')

La FOR XML PATH('') concatène essentiellement vos chaînes en un seul et long résultat XML (quelque chose comme ,code1,code2,code3 etc.) et la STUFF place un caractère "rien" au premier caractère, par exemple. supprime la première virgule "superflue" pour vous donner le résultat que vous recherchez probablement.

UPDATE: OK - Je comprends les commentaires - si votre texte dans la table de la base de données contient déjà des caractères tels que <, > ou &, alors ma solution actuelle les encodera en &lt;, &gt; et &amp; .

Si vous avez un problème avec ce codage XML - alors oui, vous devez également consulter la solution proposée par @KM, qui fonctionne également pour ces caractères. Un mot de avertissement de moi: cette approche est beaucoup plus beaucoup de ressources et de traitement - comme vous le savez. 

76
marc_s
DECLARE @CodeNameString varchar(max)
SET @CodeNameString=''

SELECT @CodeNameString=@CodeNameString+CodeName FROM AccountCodes ORDER BY Sort
SELECT @CodeNameString
24
AlexanderMP

La réponse de @ AlexanderMP est correcte, mais vous pouvez également envisager de traiter les valeurs null avec coalesce:

declare @CodeNameString  nvarchar(max)
set @CodeNameString = null
SELECT @CodeNameString = Coalesce(@CodeNameString + ', ', '') + cast(CodeName as varchar) from AccountCodes  
select @CodeNameString
10
James Wiseman

Pour SQL Server 2005 et versions ultérieures, utilisez Coalesce for nulls et j'utilise Cast ou Convert s'il existe numeric values

declare @CodeNameString  nvarchar(max)
select  @CodeNameString = COALESCE(@CodeNameString + ',', '')  + Cast(CodeName as varchar) from AccountCodes  ORDER BY Sort
select  @CodeNameString
4
Vishal

from msdn N'utilisez pas de variable dans une instruction SELECT pour concaténer des valeurs (c'est-à-dire pour calculer des valeurs d'agrégat). Des résultats de requête inattendus peuvent se produire. En effet, il n'est pas garanti que toutes les expressions de la liste SELECT (y compris les affectations) soient exécutées exactement une fois pour chaque ligne de sortie.

Ce qui précède semble indiquer que la concaténation effectuée de la manière susmentionnée n’est pas valide, car l’attribution pourrait être effectuée plus de fois que le nombre de lignes renvoyées par la sélection

2
peter

Voici un autre exemple concret qui fonctionne bien au moins avec la version 2008 (et ultérieure).

C'est la requête originale qui utilise la simple max() pour obtenir au moins une des valeurs:

SELECT option_name, Field_M3_name, max(Option_value) AS "Option value", max(Sorting) AS "Sorted"
FROM Value_list group by Option_name, Field_M3_name
ORDER BY option_name, Field_M3_name

Version améliorée, où l'amélioration principale consiste à afficher toutes les valeurs séparées par des virgules:

SELECT from1.keys, from1.option_name, from1.Field_M3_name,

 Stuff((SELECT DISTINCT ', ' + [Option_value] FROM Value_list from2
  WHERE COALESCE(from2.Option_name,'') + '|' + COALESCE(from2.Field_M3_name,'') = from1.keys FOR XML PATH(''),TYPE)
  .value('text()[1]','nvarchar(max)'),1,2,N'') AS "Option values",

 Stuff((SELECT DISTINCT ', ' + CAST([Sorting] AS VARCHAR) FROM Value_list from2
  WHERE COALESCE(from2.Option_name,'') + '|' + COALESCE(from2.Field_M3_name,'') = from1.keys FOR XML PATH(''),TYPE)
  .value('text()[1]','nvarchar(max)'),1,2,N'') AS "Sorting"

FROM ((SELECT DISTINCT COALESCE(Option_name,'') + '|' + COALESCE(Field_M3_name,'') AS keys, Option_name, Field_M3_name FROM Value_list)
-- WHERE
) from1
ORDER BY keys

Notez que nous avons résolu tous les problèmes de cas NULL possibles auxquels je peux penser et nous avons également corrigé une erreur que nous avons eue pour les valeurs numériques (champ Tri).

0
Timo Riikonen