Question

Serait-il possible de construire SQL aux valeurs de colonnes de concaténer plusieurs lignes?

Voici un exemple:

Tableau A

PID
A
B
C

Tableau B

PID   SEQ    Desc

A     1      Have
A     2      a nice
A     3      day.
B     1      Nice Work.
C     1      Yes
C     2      we can 
C     3      do 
C     4      this work!

Sortie de SQL doit être -

PID   Desc
A     Have a nice day.
B     Nice Work.
C     Yes we can do this work!

Donc, fondamentalement, la colonne Desc pour sortir la table de vente est une concaténation des valeurs de SEQ du tableau B?

Toute aide avec le SQL?

Était-ce utile?

La solution

Il y a quelques façons selon la version que vous avez - consultez la documentation oracle sur les techniques d'agrégation chaîne . Une très courante consiste à utiliser LISTAGG :

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

Alors rejoignez à A pour choisir la pids que vous voulez.

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

Autres conseils

Il y a aussi une fonction XMLAGG, qui fonctionne sur les versions antérieures à 11.2. Parce que WM_CONCAT est non documentée 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 faire ce qui suit:

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

Qu'est-ce que cela fait est

  • mettre les valeurs de la colonne de ename (concaténé avec une virgule) à partir de la table de employee_names dans un élément XML (avec étiquette E)
  • extraire le texte de cette
  • agréger les données XML (concaténer)
  • appeler la colonne résultante "Résultat"

Avec clause type 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 au sujet de cette . Et si vous suivez le lien vers le OTN-fil, vous trouverez un peu plus, y compris une comparaison des performances.

LISTAGG fonction analytique a été introduit dans Oracle 11g Release 2 , ce qui rend très facile à cordes total. Si vous utilisez 11g Release 2, vous devez utiliser cette fonction pour l'agrégation de chaîne. S'il vous plaît se référer ci-dessous URL pour plus d'informations sur la concaténation de chaîne.

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

Concaténation

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

  

ORA-01489: résultat de concaténation de chaîne est trop longue

Une nouvelle fonctionnalité dans 12cR2 est la clause ON OVERFLOW de LISTAGG. La requête, y compris 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 pas jeter l'erreur ORA-01489.

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

  • ON OVERFLOW TRUNCATE 'Contd..': Ceci affichera 'Contd..' à la fin de la chaîne (par défaut ...)
  • ON OVERFLOW TRUNCATE '': Cela permet d'afficher les 4000 caractères sans aucune chaîne de terminaison.
  • ON OVERFLOW TRUNCATE WITH COUNT: Cela permet d'afficher le total nombre de caractères à la fin après que les caractères de terminaison. Par exemple: - '...(5512)'
  • ON OVERFLOW ERROR: Si vous attendez la LISTAGG échouer avec le erreur de ORA-01489 (qui est par défaut de toute façon).

Pour ceux qui doivent résoudre ce problème en utilisant Oracle 9i (ou plus tôt), vous aurez probablement besoin d'utiliser SYS_CONNECT_BY_PATH, puisque LISTAGG n'est pas disponible.

Pour répondre à l'OP, la requête suivante affiche le PID du tableau A et concaténer toutes les colonnes du tableau B DESC:

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 aussi y avoir des cas où les clés et les valeurs sont toutes contenues dans une table. La requête suivante peut être utilisé là où il n'y a pas le tableau A, et seulement existe Tableau 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 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és comme vous le souhaitez. descriptions concaténés individuelles peuvent être réorganisés dans la clause PARTITION BY, et la liste des PIDs peuvent être réorganisés dans l'ordonnance définitive PAR clause.


Alternativement:. il peut y avoir des moments où vous voulez concaténer toutes les valeurs d'une table entière en une seule ligne

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

Dans la requête suivante, la chaîne constante « 1 » est utilisé, 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;

Par descriptions concaténer peuvent être réorganisés 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

  1. LISTAGG offre les meilleures performances si le tri est un must (00: 00: 05,85)

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

  2. COLLECT offre les meilleures performances si le tri n'est pas nécessaire (00: 00: 02,90):

    SELECT pid, TO_STRING(CAST(COLLECT(Desc) AS varchar2_ntt)) AS Vals FROM B GROUP BY pid;

  3. collectez avec commande est un peu plus lent (00: 00: 07,08):

    SELECT pid, TO_STRING(CAST(COLLECT(Desc ORDER BY Desc) AS varchar2_ntt)) AS Vals FROM B GROUP BY pid;

Toutes les autres techniques ont été plus lents.

Avant d'exécuter une requête de sélection, exécutez:

SET SERVEROUT ON SIZE 6000

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

Je l'aide de la LISTAGG mais retourner cette chaîne pour la chaîne Persian!

ma requête:

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

Résultat:

'A7'1 , ,4F

S'il vous plaît aidez-moi.

wow cette solution est travaillée:

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

Essayez ce code:

 SELECT XMLAGG(XMLELEMENT(E,fieldname||',')).EXTRACT('//text()') "FieldNames"
    FROM FIELD_MASTER
    WHERE FIELD_ID > 10 AND FIELD_AREA != 'NEBRASKA';

Dans la sélection où vous voulez que votre concaténation, appelez une fonction SQL.

Par exemple:

select PID, dbo.MyConcat(PID)
   from TableA;

Ensuite, pour la fonction SQL:

Function MyConcat(@PID varchar(10))
returns varchar(1000)
as
begin

declare @x varchar(1000);

select @x = isnull(@x +',', @x, @x +',') + Desc
  from TableB
    where PID = @PID;

return @x;

end

La syntaxe d'en-tête de fonction peut-être tort, mais le principe fonctionne.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top