web-dev-qa-db-fra.com

SQL: concaténer des valeurs de colonne sur une seule ligne dans une chaîne séparée par une virgule

Disons que j'ai une table comme celle-ci dans SQL Server:

Id    City           Province             Country
1     Vancouver      British Columbia     Canada
2     New York       null                 null
3     null           Adama                null
4     null           null                 France
5     Winnepeg       Manitoba             null
6     null           Quebec               Canada
7     Seattle        null                 USA 

Comment puis-je obtenir un résultat de requête afin que l'emplacement soit une concaténation de la ville, de la province et du pays séparés par ",", avec des valeurs nulles omises. Je voudrais m'assurer qu'il n'y a pas de virgule de fin, de virgule précédente ou de chaîne vide. Par exemple:

Id    Location
1     Vancouver, British Columbia, Canada
2     New York
3     Adama
4     France
5     Winnepeg, Manitoba
6     Quebec, Canada
7     Seattle, USA
15
Johnny Oshika

Je pense que cela règle tous les problèmes que j'ai repérés dans d'autres réponses. Pas besoin de tester la longueur de la sortie ou de vérifier si le premier caractère est une virgule, pas de souci de concaténation des types non-chaîne, pas d'augmentation significative de la complexité lorsque d'autres colonnes (par exemple Code Postal) sont inévitablement ajoutées ...

DECLARE @x TABLE(Id INT, City VARCHAR(32), Province VARCHAR(32), Country VARCHAR(32));

INSERT @x(Id, City, Province, Country) VALUES
(1,'Vancouver','British Columbia','Canada'),
(2,'New York' , null             , null   ),
(3, null      ,'Adama'           , null   ),
(4, null      , null             ,'France'),
(5,'Winnepeg' ,'Manitoba'        , null   ),
(6, null      ,'Quebec'          ,'Canada'),
(7,'Seattle'  , null             ,'USA'   );

SELECT Id, Location = STUFF(
      COALESCE(', ' + RTRIM(City),     '') 
    + COALESCE(', ' + RTRIM(Province), '') 
    + COALESCE(', ' + RTRIM(Country),  '')
    , 1, 2, '')
  FROM @x;

SQL Server 2012 a ajouté une nouvelle fonction T-SQL appelée CONCAT , mais elle n'est pas utile ici, car vous devez toujours inclure éventuellement des virgules entre les valeurs découvertes, et il n'y a aucune possibilité de faites cela - il ne fait que fusionner les valeurs sans aucune option pour un séparateur. Cela évite d'avoir à se soucier des types non-chaîne, mais ne vous permet pas de gérer les nulls vs non-nulls de manière très élégante.

36
Aaron Bertrand
select Id ,   
 Coalesce( City + ',' +Province + ',' + Country,
           City+ ',' + Province,
           Province + ',' + Country,
           City+ ',' + Country,
           City,
           Province,
           Country
          ) as location
from table
10
Kevin

C'est un problème difficile, car les virgules doivent se situer entre les deux:

select id, coalesce(city+', ', '')+coalesce(province+', ', '')+coalesce(country, '')
from t

semble que cela devrait fonctionner, mais nous pouvons obtenir une virgule superflue à la fin, comme lorsque le pays est NULL. Donc, ça doit être un peu plus compliqué:

select id,
       (case when right(val, 2) = ', ' then left(val, len(val) - 1)
             else val
        end) as val
from (select id, coalesce(city+', ', '')+coalesce(province+', ', '')+coalesce(country, '') as val
      from t
     ) t

Sans beaucoup de logique intermédiaire, je pense que le moyen le plus simple est d'ajouter une virgule à chaque élément, puis de supprimer toute virgule superflue à la fin.

3
Gordon Linoff

Utilisez l'opérateur "+".

Comprenez que les valeurs nulles ne fonctionnent pas avec l'opérateur '+' (donc par exemple: 'Winnepeg' + null = null), assurez-vous donc d'utiliser les fonctions ISNULL () ou COALESCE () pour remplacer les nulls par une chaîne vide, par exemple: ISNULL ('Winnepeg', '') + ISNULL (null, '').

De plus, s'il est même possible à distance qu'une de vos colonnes puisse être interprétée comme un nombre, assurez-vous également d'utiliser la fonction CAST (), afin d'éviter les retours d'erreur, par exemple: CAST ('Winnepeg' as varchar ( 100)).

Jusqu'à présent, la plupart des exemples en négligent un ou plusieurs éléments. De plus, certains exemples utilisent des sous-requêtes ou effectuent une vérification de la longueur, ce que vous ne devriez vraiment pas faire - tout simplement pas nécessaire - bien que votre optimiseur puisse vous sauver de toute façon si vous le faites.

Bonne chance

2
Chains

laid mais cela fonctionnera pour MS SQL:

    select
    id,
    case
        when right(rtrim(coalesce(city + ', ','') + coalesce(province + ', ','') + coalesce(country,'')),1)=',' then left(rtrim(coalesce(city + ', ','') + coalesce(province + ', ','') + coalesce(country,'')),LEN(rtrim(coalesce(city + ', ','') + coalesce(province + ', ','') + coalesce(country,'')))-1)
        else rtrim(coalesce(city + ', ','') + coalesce(province + ', ','') + coalesce(country,''))
    end
from
    table
1
Phil