2009-06-09 10 views
23

Comment concaténer toutes les valeurs de colonnes de différentes lignes renvoyées à partir d'une requête sql en une valeur? Voici un exemple:Concat toutes les valeurs de colonne en sql

une requête renvoie:

 
FOO 
------ 
RES1 

RES2 

RES3 

maintenant je veux avoir un résultat comme le suivant:

 
FOOCONCAT 
----- 
RES1RES2RES3 

Existe-t-il des façons de le faire dans sql?

+0

Quel serveur utilisez-vous? Je doute qu'il existe une méthode SQL générique pour le faire, mais il existe certainement des méthodes spécifiques à l'implémentation. –

+1

J'utilise Oracle. Je suis étonné qu'il n'y ait pas de moyen facile de le faire en oracle. – paweloque

Répondre

0
select cast(res1 as varchar)+cast(res2 as varchar)+cast(res3 as varchar) as fooconcat from foo 

Si les colonnes sont des chaînes déjà que vous n'avez pas besoin du casting, vous pouvez juste faire:

select res1 + res2 + res3 as fooconcat from foo 

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

+0

et comment faites-vous la même chose pour un nombre arbitraire de valeurs? – paweloque

+0

res1, res2 et res3 ne sont pas des colonnes mais des valeurs. La colonne est "foo". – paweloque

+0

Désolé, lorsque j'ai répondu à cette question vos données ont été formatées sur une seule ligne, donc la question semblait être différente. – RedFilter

40

En SQL Server:

SELECT col1 AS [text()] 
FROM foo 
FOR XML PATH ('') 

En MySQL:

SELECT GROUP_CONCAT(col1 SEPARATOR '') 
FROM foo 

En PostgreSQL:

SELECT array_to_string 
     (
     ARRAY 
     (
     SELECT col1 
     FROM foo 
     ), '' 
     ) 

En Oracle:

SELECT * 
FROM (
     SELECT col1, ROW_NUMBER() OVER(ORDER BY 1) AS rn 
     FROM foo 
     MODEL 
     DIMENSION BY 
       (rn) 
     MEASURES 
       (col1, col1 AS group_concat, 0 AS mark) 
     RULES UPDATE (
       group_concat[rn > 1] = group_concat[CV() - 1] || col1[CV()], 
       mark[ANY] = PRESENTV(mark[CV() + 1], 0, 1) 
       ) 
     ) 
WHERE mark = 1 
+1

ressemble à une solution, mais à quoi cela ressemblerait-il dans Oracle? – paweloque

+1

@lewap: Patience! – Quassnoi

+0

C'est une astuce cool dans SQL Server, je voudrais juste changer le select à: SELECT REPLACE (REMPLACE (col1, '', ''), '', '') – RedFilter

0

Concaténation dépend de la base de données que vous utilisez (vous havnt mentionné dans quelle version votre question ici va donc) ...

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

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

MySQL est CONCAT(string, string... n_string)

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

... J'ai sorti ça de ce petit livre sympa que j'ai assis sur mon bureau Guide de poche SQL d'O'Reilly ... jetez un coup d'œil!

:)

+1

Ceux qui fonctionnent vraiment seulement avec des chaînes de la même rangée. –

+0

Je sais ce que vous voulez dire, vous feriez quelque chose comme ... Sélectionnez @Text = @Text + RES, ou sélectionnez @Text = CONCAT (@Text, RES) etc pour concaténer les colonnes. –

3

En supposant que c'est une colonne avec plusieurs valeurs, cette approche fonctionne pour MS SQL Server (je ne peux pas parler pour les autres systèmes).

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

select @result = @result + RES 
from (query goes here) 
0

Il pourrait ne pas être ce que vous cherchez, mais je l'ai eu de la chance dans le passé avec des constructions comme ceci:

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; 

Il est indépendant de la plateforme, et il fonctionne bien lorsque vous avoir un nombre arbitraire, mais limité de valeurs pour foo, et ils sont basés sur une autre valeur clé.Par exemple, si vous avez une table de factures et que vous voulez voir toutes les lignes de la facture sur une seule ligne concaténée et que vous avez une limite supérieure de 5 lignes, cela ressemblera à 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; 
3

la façon mysql:

select group_concat(somecolumn separator '') from sometable 
+0

avéré ne pas être tout à fait ce dont j'avais besoin, mais je peux dire que ça va être vraiment utile parfois – jsh

1

Voici la réponse que vous cherchez; J'avais l'impression que la solution résidait dans l'opération CONNECT BY, je n'avais tout simplement pas utilisé la pseudo-colonne SYS_CONNECT_BY_PATH auparavant (qui affiche le chemin complet du nœud dans une arborescence, en séparant les noms de nœuds par un "/"). En supposant que votre ensemble de valeurs « foo » avant sont plusieurs lignes d'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 si elles étaient un schéma d'arbre, et prétendre que les valeurs de chaque groupe représentent les 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 sûr, l'ordre des valeurs concaténées serait aléatoire; si votre table avait une autre colonne ("barre") que vous pourriez utiliser comme un champ d'ordre ascendant et contigu, vous pouvez vous passer de la sous-requête (qui n'existe que pour mettre une profondeur imaginaire dans l'arbre) et utiliser directement la table, remplacer NodeDepth par une barre.

8

La solution Oracle de Quassnoi est assez impressionnante, mais j'ai foundsimpler en utilisant SYS_CONNECT_BY_PATH() plutôt que la magie MODEL.

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; 
+0

Nice, je pouvais utiliser cela. Bon travail. – contactmatt

-2

Select ([col1] + ' '+ [col2] +', '+ [col3] +',' + [col4]) comme [MyCol] De [Tableau]

+3

le but est de concaténer des lignes, pas des colonnes –

1

Edit: Depuis la version 8.4.0 CUBRID fournit 90% compatibility avec MySQL. Ainsi, il prend en charge GROUP_CONCAT qui a une syntaxe similaire à 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, est-ce pas? Et ci-dessous est un alternative solution pris en charge 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; 

Il est si intéressant que cette façon de concaténer des valeurs différentes de la colonne de ligne dans CUBRID est presque identique à la façon d'Oracle comme prévu par @devio. Dans CUBRID, cela semble un peu plus facile.

0

SQL Server 2008 R2:

declare @ColumnNameList VARCHAR(MAX) 


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

select @ColumnNameList 
Questions connexes