web-dev-qa-db-fra.com

Requête SQL pour concaténer les valeurs de colonne de plusieurs lignes dans Oracle

Serait-il possible de construire SQL pour concaténer les valeurs de colonne de Plusieurs lignes? 

Ce qui suit est un exemple: 

Tableau a

 PID 
 A 
 B 
 C 

Tableau b

 PID SEQ Desc 

 A 1 Avoir 
 A 2 a Nice 
 A 3 jours .
 B 1 Bel ouvrage .
 C 1 Oui 
 C 2 nous pouvons 
 C 3 do 
 C 4 ce travail! 

La sortie du SQL devrait être -

 PID Desc 
 Bonne journée .
 B Beau travail .
 C Oui, nous pouvons faire ce travail! 

Donc, fondamentalement, la colonne Desc pour la table de sorties est une concaténation des valeurs SEQ de la table B?

Toute aide avec le SQL?

124
jagamot

Selon votre version, vous disposez de plusieurs méthodes - voir la documentation Oracle sur les techniques d'agrégation de chaînes Un très commun consiste à utiliser LISTAGG :

SELECT pid, LISTAGG(Desc, ' ') WITHIN GROUP (ORDER BY seq) AS description
FROM B GROUP BY pid;

Joignez-vous ensuite à A pour choisir la pids souhaitée.

Remarque: Hors de la boîte, LISTAGG ne fonctionne correctement qu'avec les colonnes VARCHAR2.

186
Lou Franco

Il existe également une fonction XMLAGG, qui fonctionne sur les versions antérieures à 11.2. Étant donné que WM_CONCAT est non documenté et non pris en charge par Oracle , il est recommandé de ne pas l'utiliser dans le système de production.

Avec XMLAGG, vous pouvez effectuer les opérations suivantes:

SELECT XMLAGG(XMLELEMENT(E,ename||',')).EXTRACT('//text()') "Result" 
FROM employee_names

Qu'est-ce que cela fait

  • place les valeurs de la colonne ename (concaténées avec une virgule) de la table employee_names dans un élément xml (avec la balise E)
  • extraire le texte de cette
  • agréger le xml (le concaténer)
  • appeler la colonne résultante "Résultat"
17
Peter

Avec clause de modèle SQL:

SQL> select pid
  2       , ltrim(sentence) sentence
  3    from ( select pid
  4                , seq
  5                , sentence
  6             from b
  7            model
  8                  partition by (pid)
  9                  dimension by (seq)
 10                  measures (descr,cast(null as varchar2(100)) as sentence)
 11                  ( sentence[any] order by seq desc
 12                    = descr[cv()] || ' ' || sentence[cv()+1]
 13                  )
 14         )
 15   where seq = 1
 16  /

P SENTENCE
- ---------------------------------------------------------------------------
A Have a Nice day
B Nice Work.
C Yes we can do this work!

3 rows selected.

J'ai écrit à ce sujet ici . Et si vous suivez le lien vers le fil OTN, vous en trouverez d'autres, y compris une comparaison des performances.

11
Rob van Wijk

La fonction analytique LISTAGG a été introduite dans Oracle 11g version 2, ce qui facilite grandement l'agrégation des chaînes . Si vous utilisez la version 2 de 11g, vous devez utiliser cette fonction pour l’agrégation de chaînes . Veuillez vous reporter ci-dessous à l’URL pour plus d’informations sur la concaténation de chaînes.

http://www.Oracle-base.com/articles/misc/StringAggregationTechniques.php

Concaténation de cordes

7
Ashish J

Comme le suggèrent la plupart des réponses, LISTAGG est l'option évidente. Cependant, un aspect gênant avec LISTAGG est que si la longueur totale de la chaîne concaténée dépasse 4000 caractères (limite pour VARCHAR2 en SQL), l'erreur ci-dessous est renvoyée, ce qui est difficile à gérer dans les versions Oracle jusqu'à 12.1 

ORA-01489: le résultat de la concaténation de chaînes est trop long

Une nouvelle fonctionnalité ajoutée dans 12cR2 est la clause ON OVERFLOW de LISTAGG. La requête incluant cette clause ressemblerait à ceci:

SELECT pid, LISTAGG(Desc, ' ' on overflow truncate) WITHIN GROUP (ORDER BY seq) AS desc
FROM B GROUP BY pid;

Ce qui précède limitera la sortie à 4000 caractères, mais ne générera pas l'erreur ORA-01489.

Voici quelques-unes des options supplémentaires de la clause ON OVERFLOW:

  • ON OVERFLOW TRUNCATE 'Contd..': Ceci affichera 'Contd..' à la fin de la chaîne (la valeur par défaut est ...)
  • ON OVERFLOW TRUNCATE '': Ceci affichera les 4000 caractères sans chaîne de fin.
  • ON OVERFLOW TRUNCATE WITH COUNT: Ceci affichera le nombre total de caractères à la fin après les caractères finaux . Exemple: - '...(5512)'
  • ON OVERFLOW ERROR: Si vous vous attendez à ce que LISTAGG échoue avec l'erreur ORA-01489 (qui est par défaut de toute façon).
6
Kaushik Nayak

Pour ceux qui doivent résoudre ce problème avec Oracle 9i (ou une version antérieure), vous devrez probablement utiliser SYS_CONNECT_BY_PATH, car LISTAGG n’est pas disponible.

Pour répondre à l'OP, la requête suivante affiche le PID de la table A et concatène toutes les colonnes DESC de la table B:

SELECT pid, SUBSTR (MAX (SYS_CONNECT_BY_PATH (description, ', ')), 3) all_descriptions
FROM (
       SELECT ROW_NUMBER () OVER (PARTITION BY pid ORDER BY pid, seq) rnum, pid, description
       FROM (
              SELECT a.pid, seq, description
              FROM table_a a, table_b b
              WHERE a.pid = b.pid(+)
             )
      )
START WITH rnum = 1
CONNECT BY PRIOR rnum = rnum - 1 AND PRIOR pid = pid
GROUP BY pid
ORDER BY pid;

Il peut également y avoir des cas où les clés et les valeurs sont toutes contenues dans une même table. La requête suivante peut être utilisée lorsqu'il n'y a pas de table A et que seule la table B existe:

SELECT pid, SUBSTR (MAX (SYS_CONNECT_BY_PATH (description, ', ')), 3) all_descriptions
FROM (
       SELECT ROW_NUMBER () OVER (PARTITION BY pid ORDER BY pid, seq) rnum, pid, description
       FROM (
              SELECT pid, seq, description
              FROM table_b
             )
      )
START WITH rnum = 1
CONNECT BY PRIOR rnum = rnum - 1 AND PRIOR pid = pid
GROUP BY pid
ORDER BY pid;

Toutes les valeurs peuvent être réorganisées à volonté. Les descriptions concaténées individuelles peuvent être réorganisées dans la clause PARTITION BY et la liste des PID peut être réorganisée dans la clause finale ORDER BY.


Alternativement: il peut arriver que vous souhaitiez concaténer toutes les valeurs d'un tableau entier dans une ligne.

L'idée clé ici est d'utiliser une valeur artificielle pour le groupe de descriptions à concaténer.

Dans la requête suivante, la chaîne constante '1' est utilisée, mais toute valeur fonctionnera:

SELECT SUBSTR (MAX (SYS_CONNECT_BY_PATH (description, ', ')), 3) all_descriptions
FROM (
       SELECT ROW_NUMBER () OVER (PARTITION BY unique_id ORDER BY pid, seq) rnum, description
       FROM (
              SELECT '1' unique_id, b.pid, b.seq, b.description
              FROM table_b b
             )
      )
START WITH rnum = 1
CONNECT BY PRIOR rnum = rnum - 1;

Les descriptions concaténées individuelles peuvent être réorganisées dans la clause PARTITION BY.

Plusieurs autres réponses sur cette page ont également mentionné cette référence extrêmement utile: https://Oracle-base.com/articles/misc/string-aggregation-techniques

3
JonathanDavidArndt

Avant de lancer une requête de sélection, lancez ceci: 

SET SERVEROUT ON SIZE 6000 

SELECT XMLAGG(XMLELEMENT(E,SUPLR_SUPLR_ID||',')).EXTRACT('//text()') "SUPPLIER" 
FROM SUPPLIERS;
1
user2865810

J'utilise le LISTAGG mais retourne cette chaîne pour la chaîne persane!

ma requête:

SELECT
 listagg(DESCRIPTION,' , ') within group (order by DESCRIPTION) 
FROM
B_CEREMONY

résultat:

'A7'1 , ,4F

Aidez-moi, s'il vous plaît.

wow cette solution est travaillée:

SELECT listagg(convert(DESCRIPTION, 'UTF8', 'AL16UTF16'),' , ') within group 
(order by DESCRIPTION) 
FROM  B_CEREMONY;
0
Ghasem Aladaghlou