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?
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;
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)
Le chemin mysql:
select group_concat(somecolumn separator '') from sometable
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.
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.
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
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!
:)
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;
SQL Server 2008 R2:
declare @ColumnNameList VARCHAR(MAX)
SELECT @ColumnNameList = COALESCE(@ColumnNameList +',' ,'') + ColumnName
FROM
<<table name>>
select @ColumnNameList
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 .