51 votes

Convertir une chaîne séparée par des virgules en tableau en PL/SQL

Comment convertir une chaîne séparée par des virgules en un tableau ?

J'ai l'entrée ' 1,2,3' et je dois le convertir en tableau.

75voto

Richard Sylvester Points 711

Voici une autre option plus facile

select to_number(column_value) as IDs from xmltable('1,2,3,4,5');

0 votes

C'est exactement ce dont j'ai besoin ! Je n'ai que des chiffres ! (y)

3 votes

Wow ! Cela se lit si bien pour PL/SQL : FOR i IN (SELECT to_number(column_value) as ID FROM xmltable('1,2,3,4,5')) LOOP... END LOOP; est tout simplement excellent, merci !

0 votes

Hélas, cela donne ORA-01460: unimplemented or unreasonable conversion requested pour une ligne d'une longueur >4 000 octets

35voto

Rob van Wijk Points 11088

Oracle fournit la fonction intégrée DBMS_UTILITY.COMMA_TO_TABLE .

Malheureusement, celle-ci ne fonctionne pas avec les chiffres :

SQL> declare
  2    l_input varchar2(4000) := '1,2,3';
  3    l_count binary_integer;
  4    l_array dbms_utility.lname_array;
  5  begin
  6    dbms_utility.comma_to_table
  7    ( list   => l_input
  8    , tablen => l_count
  9    , tab    => l_array
 10    );
 11    dbms_output.put_line(l_count);
 12    for i in 1 .. l_count
 13    loop
 14      dbms_output.put_line
 15      ( 'Element ' || to_char(i) ||
 16        ' of array contains: ' ||
 17        l_array(i)
 18      );
 19    end loop;
 20  end;
 21  /
declare
*
ERROR at line 1:
ORA-00931: missing identifier
ORA-06512: at "SYS.DBMS_UTILITY", line 132
ORA-06512: at "SYS.DBMS_UTILITY", line 164
ORA-06512: at "SYS.DBMS_UTILITY", line 218
ORA-06512: at line 6

Mais avec une petite astuce consistant à préfixer les éléments par un "x", cela fonctionne :

SQL> declare
  2    l_input varchar2(4000) := '1,2,3';
  3    l_count binary_integer;
  4    l_array dbms_utility.lname_array;
  5  begin
  6    dbms_utility.comma_to_table
  7    ( list   => regexp_replace(l_input,'(^|,)','\1x')
  8    , tablen => l_count
  9    , tab    => l_array
 10    );
 11    dbms_output.put_line(l_count);
 12    for i in 1 .. l_count
 13    loop
 14      dbms_output.put_line
 15      ( 'Element ' || to_char(i) ||
 16        ' of array contains: ' ||
 17        substr(l_array(i),2)
 18      );
 19    end loop;
 20  end;
 21  /
3
Element 1 of array contains: 1
Element 2 of array contains: 2
Element 3 of array contains: 3

PL/SQL procedure successfully completed.

Regards, Rob.

0 votes

Bonne prise. Cela ne fonctionne pas non plus avec les caractères spéciaux. Vous pouvez contourner cette limitation en effectuant des "remplacements" spéciaux. Par exemple, utilisez replace(...,' ', 'XYZ') lorsque vous entrez dans la fonction et replace(..., 'XYZ',' ') lorsque vous récupérez les valeurs individuelles.

2 votes

De : Conversion de listes délimitées en collections (et vice versa) _COMMA_TO_TABLE (et l'inverse TABLE_TO_COMMA ) ne sont pas écrits dans ce but !_ ... Ils sont écrits principalement pour être utilisés dans le cadre de la réplication interne d'Oracle, et analysent les IDENTIFIERS plutôt que les chaînes de caractères, et en tant que tels doivent être des noms d'objets Oracle valides.

1 votes

Erreur lors de l'utilisation d'une chaîne avec "." Ex : '8.5.17.1,8.5.17.2' L'erreur est ORA-20001: comma-separated list invalid near x8.5. Pouvez-vous nous aider à résoudre ce problème ?

21voto

Ray Cheng Points 3939

On ne peut jamais être à court d'alternatives pour faire la même chose différemment, n'est-ce pas ? J'ai récemment découvert que c'était très pratique :

DECLARE
   BAR   VARCHAR2 (200) := '1,2,3';
BEGIN
   FOR FOO IN (    SELECT REGEXP_SUBSTR (BAR,
                                         '[^,]+',
                                         1,
                                         LEVEL)
                             TXT
                     FROM DUAL
               CONNECT BY REGEXP_SUBSTR (BAR,
                                         '[^,]+',
                                         1,
                                         LEVEL)
                             IS NOT NULL)
   LOOP
      DBMS_OUTPUT.PUT_LINE (FOO.TXT);
   END LOOP;
END;

Sorties :

1
2
3

0 votes

Une expression très belle et logiquement construite :-)

0 votes

Ne fonctionne pas si vous avez une chaîne vide au milieu (par exemple '1,2,,3').

0 votes

Cette méthode ne fonctionne efficacement que pour les petites listes, car elle produit une jonction croisée avant de sélectionner les lignes pour lesquelles le nombre de correspondances correspondant ( LEVEL ) est le même. Si vos listes sont susceptibles d'augmenter au fil du temps, cela présente un risque d'évolutivité.

15voto

Malvineous Points 2416

Je sais que Stack Overflow désapprouve le collage d'URL sans explications, mais cette page particulière propose quelques très bonnes options :

http://www.oratechinfo.co.uk/delimited_lists_to_collections.html

J'aime particulièrement celle-ci, qui convertit la liste délimitée en un tableau temporaire sur lequel vous pouvez exécuter des requêtes :

/* Create the output TYPE, here using a VARCHAR2(100) nested table type */

SQL> CREATE TYPE test_type AS TABLE OF VARCHAR2(100);
  2  /

Type created.

/* Now, create the function.*/

SQL> CREATE OR REPLACE FUNCTION f_convert(p_list IN VARCHAR2)
  2    RETURN test_type
  3  AS
  4    l_string       VARCHAR2(32767) := p_list || ',';
  5    l_comma_index  PLS_INTEGER;
  6    l_index        PLS_INTEGER := 1;
  7    l_tab          test_type := test_type();
  8  BEGIN
  9    LOOP
 10      l_comma_index := INSTR(l_string, ',', l_index);
 11      EXIT WHEN l_comma_index = 0;
 12      l_tab.EXTEND;
 13      l_tab(l_tab.COUNT) := SUBSTR(l_string, l_index, l_comma_index - l_index);
 14      l_index := l_comma_index + 1;
 15    END LOOP;
 16    RETURN l_tab;
 17  END f_convert;
 18  /

Function created.

/* Prove it works */

SQL> SELECT * FROM TABLE(f_convert('AAA,BBB,CCC,D'));

COLUMN_VALUE
--------------------------------------------------------------------------------
AAA
BBB
CCC
D

4 rows selected.

0 votes

Cette solution est la seule qui fonctionne si vous avez une chaîne avec des espaces et des virgules consécutives (par exemple 12 3,456,,abc,def). J'ai cherché pendant 4 heures, jusqu'à ce que je trouve ceci !!!!!!

4voto

Rocky Points 49

Code simple

    create or replace function get\_token(text\_is varchar2, token\_in number, delim\_is varchar2 := ';') return varchar2 is
       text\_ls varchar2(2000);
       spos\_ln number;
       epos    \_ln number;
    begin
       text\_ls := delim\_is || text\_is || rpad(delim\_is, token\_in, delim\_is);
       spos\_ln := instr(text\_ls, delim\_is, 1, token\_in);
       epos\_ln := instr(text\_ls, delim\_is, 1, token\_in+1);
       return substr(text\_ls, spos\_ln+1, epos\_ln-spos\_ln-1);
    end get\_token;

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X