web-dev-qa-db-fra.com

Concaténer toutes les valeurs de colonne en sql

Comment concaténer toutes les valeurs de colonne provenant de différentes lignes renvoyées par une requête SQL en une seule valeur? Ceci est un exemple:

une requête renvoie:

 FOO 
 ------ 
 RES1 

 RES2 

 RES3 

maintenant je veux avoir un résultat comme celui-ci:

 FOOCONCAT 
 ----- 
 RES1RES2RES3 

Existe-t-il un moyen de faire cela en SQL?

25
paweloque

La solution Oracle de Quassnoi est assez impressionnante, mais j'ai trouvéplus simple ceux qui utilisent SYS_CONNECT_BY_PATH () plutôt que le modèle magique.

SELECT REPLACE(MAX(SYS_CONNECT_BY_PATH(foo, '/')), '/', '') conc
FROM (
    SELECT T_FOO.*, ROW_NUMBER() OVER (ORDER BY FOO) R FROM T_FOO
)
START WITH r=1
CONNECT BY PRIOR r = r-1;
8
devio

En supposant qu'il s'agisse d'une colonne avec plusieurs valeurs, cette approche fonctionne pour MS SQL Server (je ne peux pas parler pour d'autres systèmes).

declare @result varchar(max)
set @result = ''

select @result = @result + RES
from (query goes here)
3
John McLusky

Le chemin mysql:

select group_concat(somecolumn separator '') from sometable
3
ʞɔıu

Edit: Depuis la version 8.4.0, CUBRID fournit Compatibilité à 90% avec MySQL. Ainsi, il supporte GROUP_CONCAT qui a une syntaxe similaire à celle de MySQL:

CREATE TABLE t(i int);
INSERT INTO t VALUES (4),(2),(3),(6),(1),(5);

SELECT GROUP_CONCAT(i*2+1 ORDER BY 1 SEPARATOR '') FROM t;

group_concat(i*2+1 order by 1 separator '')
======================
  '35791113'

Assez puissant, n'est-ce pas? Et ci-dessous se trouve une solution alternative supportée nativement dans CUBRID.

SELECT MAX(SYS_CONNECT_BY_PATH(s_name, '')) AS conc_s_name
FROM (
     SELECT ROWNUM AS r, s_name FROM code
) AS res
START WITH r = 1
CONNECT BY PRIOR r = r - 1;

C'est tellement intéressant que cette manière de concaténer différentes valeurs de colonne de ligne dans CUBRID est presque identique à celle d'Oracle fournie par @devio. Dans CUBRID, cela semble un peu plus facile.

1
Eye

Voici la réponse que vous recherchez. J'avais l'impression que la solution reposait sur l'opération CONNECT BY. Je n'avais jamais utilisé la pseudocolonne SYS_CONNECT_BY_PATH auparavant (qui affiche le chemin complet du noeud dans un arbre, en séparant les noms de noeud par un "/"). En supposant que votre ensemble de valeurs "foo" auparavant soit constitué de plusieurs lignes dans une table, regroupées par une colonne "myKey", par exemple:

myKey    foo
-------- ----------
group 1  Apple
group 1  orange
group 1  pear
group 2  ape
group 2  bear
group 2  kitten

vous pouvez traiter les données comme s'il s'agissait d'un schéma d'arborescence et prétendre que les valeurs de chaque groupe représentent des nœuds descendant d'une branche. Dans ce cas, vous feriez ceci:

  SELECT myKey
       , SUBSTR(MAX(REPLACE(SYS_CONNECT_BY_PATH(foo, '/')
                           ,'/'
                           ,' '
                           )
                   )
               ,2
               ) FooConcat
    FROM ( SELECT MyKey
                , Foo
                , row_number() OVER (Partition by myKey order by myKey) NodeDepth
             FROM MyTable
         )
   START WITH NodeDepth = 1
 CONNECT BY PRIOR myKey = myKey
     AND PRIOR NodeDepth = NodeDepth -1
GROUP BY myKey
;

Bien entendu, l'ordre des valeurs concaténées serait aléatoire; si votre table avait une autre colonne ("barre") que vous pouviez utiliser comme champ de classement ascendant et contigu, vous pourriez vous passer de la sous-requête (qui n'existe que pour mettre une profondeur imaginaire dans l'arbre) et utiliser directement le tableau, remplacer NodeDepth par bar.

1
Steve Broberg

J'ai trouvé la réponse sur Comment concaténer tous les enregistrements d'une colonne renvoyés par une requête en une chaîne varchar dans T-SQL?

declare @s varchar(8000)
select @s = coalesce(@s + col, col) from tbl

Cela devrait résoudre 

0
navya

La concaténation des chaînes dépend de la base de données que vous utilisez (vous n’avez pas mentionné la version de votre question, alors voilà) ...

Dans Oracle et DB2, vous pouvez utiliser la fonction CONCAT ... CONCAT(string, string) 

SQL Server, vous pouvez utiliser l'opérateur '+' ... string1 + string2 + string3 

Dans MySQL, c'est CONCAT(string, string... n_string) 

Enfin dans PostgreSQL, c’est TEXTCAT(string, string)... 

... j'ai trouvé ceci dans ce petit livre cool que j'ai assis sur mon bureau Guide de poche SQL de O'Reilly ... testez-le!

:)

0
user110714

Ce n'est peut-être pas ce que vous cherchez, mais j'ai déjà eu de la chance avec des constructions comme celle-ci:

SELECT      MAX(DECODE(fookey, 1, foo, NULL))
         || MAX(DECODE(fookey, 2, foo, NULL))
         || MAX(DECODE(fookey, 3, foo, NULL))
         || MAX(DECODE(fookey, 4, foo, NULL))
       , groupingvalue
    FROM mytable
GROUP BY groupingvalue;

Elle est indépendante de la plate-forme et fonctionne bien lorsque vous avez un nombre arbitraire, mais limité, de valeurs pour foo, basées sur une autre valeur clé. Par exemple, si vous avez un tableau de factures et que vous voulez voir tous les temps de ligne de la facture sur une seule ligne, concaténés, et que vous ayez une limite supérieure de 5 éléments de ligne, cela ressemblerait à ceci:

SELECT      MAX(DECODE(lineno, 1, foo, NULL))
         || ', '
         || MAX(DECODE(lineno, 2, foo, NULL))
         || ', '
         || MAX(DECODE(lineno, 3, foo, NULL))
         || ', '
         || MAX(DECODE(lineno, 4, foo, NULL))
         || ', '
         || MAX(DECODE(lineno, 5, foo, NULL))
       , invoiceid
    FROM lineitem
GROUP BY invoiceid;
0
Steve Broberg

SQL Server 2008 R2:

declare @ColumnNameList VARCHAR(MAX)


 SELECT @ColumnNameList  = COALESCE(@ColumnNameList +',' ,'') + ColumnName 
                     FROM 
                       <<table name>>

select @ColumnNameList 
0
Kristy Welsh
select cast(res1 as varchar)+cast(res2 as varchar)+cast(res3 as varchar) as fooconcat from foo

Si les colonnes sont déjà des chaînes, vous n'avez pas besoin de la conversion, vous pouvez simplement faire:

select res1 + res2 + res3  as fooconcat from foo

Pour les données de plusieurs lignes, utilisez PIVOT .

0
RedFilter