Convert comma separated string to array in PL/SQL

前端 未结 14 2172
没有蜡笔的小新
没有蜡笔的小新 2020-11-27 03:19

How do I convert a comma separated string to a array?

I have the input \'1,2,3\' , and I need to convert it into an array.

相关标签:
14条回答
  • 2020-11-27 03:33

    Another possibility is:

    create or replace FUNCTION getNth (
      input varchar2,
      nth number
    ) RETURN varchar2 AS
      nthVal varchar2(80);
    BEGIN
      with candidates (s,e,n) as (
          select 1, instr(input,',',1), 1 from dual
          union all
          select e+1, instr(input,',',e+1), n+1
            from candidates where e > 0)
      select substr(input,s,case when e > 0 then e-s else length(input) end) 
        into nthVal
        from candidates where n=nth;
      return nthVal;
    END getNth;
    

    It's a little too expensive to run, as it computes the complete split every time the caller asks for one of the items in there...

    0 讨论(0)
  • 2020-11-27 03:38
    TYPE string_aa IS TABLE OF VARCHAR2(32767) INDEX BY PLS_INTEGER;
    
    FUNCTION string_to_list(p_string_in IN VARCHAR2)
        RETURN string_aa
        IS
          TYPE ref_cursor IS ref cursor;
          l_cur    ref_cursor;
          l_strlist string_aa;
          l_x      PLS_INTEGER;
        BEGIN      
          IF p_string_in IS NOT NULL THEN 
             OPEN l_cur FOR 
                SELECT regexp_substr(p_string_in,'[^,]+', 1, level) FROM dual
                CONNECT BY regexp_substr(p_string_in, '[^,]+', 1, level) IS NOT NULL;      
             l_x := 1; 
             LOOP
               FETCH l_cur INTO l_strlist(l_x);
               EXIT WHEN l_cur%notfound;
               -- excludes NULL items  e.g.   1,2,,,,5,6,7
               l_x := l_x + 1;
             END LOOP;
          END IF;   
          RETURN l_strlist;
       END string_to_list;
    
    0 讨论(0)
  • 2020-11-27 03:38
    declare 
        v_str varchar2(100) := '1,2,3,4,6,7,8,9,0,';
        v_str1 varchar2(100); 
        v_comma_pos number := 0;    
        v_start_pos number := 1;
    begin             
        loop        
        v_comma_pos := instr(v_str,',',v_start_pos);   
        v_str1 := substr(v_str,v_start_pos,(v_comma_pos - v_start_pos)); 
        dbms_output.put_line(v_str1);     
        if  v_comma_pos = 0 then     
        v_str1 := substr(v_str,v_start_pos);  
        dbms_output.put_line(v_str1);    
        exit;
        end if;    
        v_start_pos := v_comma_pos + 1;  
        if  v_comma_pos = 0 then    
        exit;
        end if;       
        end loop; 
    end;
    
    0 讨论(0)
  • 2020-11-27 03:44

    Yes, it is very frustrating that dbms_utility.comma_to_table only supports comma delimieted lists and then only when elements in the list are valid PL/SQL identifies (so numbers cause an error).

    I have created a generic parsing package that will do what you need (pasted below). It is part of my "demo.zip" file, a repository of over 2000 files that support my training materials, all available at PL/SQL Obsession: www.toadworld.com/SF.

    Regards, Steven Feuerstein www.plsqlchallenge.com (daily PL/SQL quiz)

        CREATE OR REPLACE PACKAGE parse
    /*
       Generalized delimited string parsing package
    
       Author: Steven Feuerstein, steven@stevenfeuerstein.com
    
       Latest version always available on PL/SQL Obsession: 
    
       www.ToadWorld.com/SF
    
       Click on "Trainings, Seminars and Presentations" and
       then download the demo.zip file.
    
       Modification History
          Date          Change
          10-APR-2009   Add support for nested list variations
    
       Notes:
         * This package does not validate correct use of delimiters.
           It assumes valid construction of lists.
         * Import the Q##PARSE.qut file into an installation of 
           Quest Code Tester 1.8.3 or higher in order to run
           the regression test for this package.
    
    */
    IS
       SUBTYPE maxvarchar2_t IS VARCHAR2 (32767);
    
       /*
       Each of the collection types below correspond to (are returned by)
       one of the parse functions.
    
       items_tt - a simple list of strings
       nested_items_tt - a list of lists of strings
       named_nested_items_tt - a list of named lists of strings
    
       This last type also demonstrates the power and elegance of string-indexed
       collections. The name of the list of elements is the index value for
       the "outer" collection.
       */
       TYPE items_tt IS TABLE OF maxvarchar2_t
                           INDEX BY PLS_INTEGER;
    
       TYPE nested_items_tt IS TABLE OF items_tt
                                  INDEX BY PLS_INTEGER;
    
       TYPE named_nested_items_tt IS TABLE OF items_tt
                                        INDEX BY maxvarchar2_t;
    
       /*
       Parse lists with a single delimiter.
       Example: a,b,c,d
    
       Here is an example of using this function:
    
       DECLARE
          l_list parse.items_tt;
       BEGIN
          l_list := parse.string_to_list ('a,b,c,d', ',');
       END;
       */
       FUNCTION string_to_list (string_in IN VARCHAR2, delim_in IN VARCHAR2)
          RETURN items_tt;
    
       /*
       Parse lists with nested delimiters.
       Example: a,b,c,d|1,2,3|x,y,z
    
       Here is an example of using this function:
    
       DECLARE
          l_list parse.nested_items_tt;
       BEGIN
          l_list := parse.string_to_list ('a,b,c,d|1,2,3,4', '|', ',');
       END;
       */
       FUNCTION string_to_list (string_in      IN VARCHAR2
                              , outer_delim_in IN VARCHAR2
                              , inner_delim_in IN VARCHAR2
                               )
          RETURN nested_items_tt;
    
       /*
       Parse named lists with nested delimiters.
       Example: letters:a,b,c,d|numbers:1,2,3|names:steven,george
    
       Here is an example of using this function:
    
       DECLARE
          l_list parse.named_nested_items_tt;
       BEGIN
       l_list := parse.string_to_list ('letters:a,b,c,d|numbers:1,2,3,4', '|', ':', ',');
       END;
       */
       FUNCTION string_to_list (string_in      IN VARCHAR2
                              , outer_delim_in IN VARCHAR2
                              , name_delim_in  IN VARCHAR2
                              , inner_delim_in IN VARCHAR2
                               )
          RETURN named_nested_items_tt;
    
       PROCEDURE display_list (string_in IN VARCHAR2
                             , delim_in  IN VARCHAR2:= ','
                              );
    
       PROCEDURE display_list (string_in      IN VARCHAR2
                             , outer_delim_in IN VARCHAR2
                             , inner_delim_in IN VARCHAR2
                              );
    
       PROCEDURE display_list (string_in      IN VARCHAR2
                             , outer_delim_in IN VARCHAR2
                             , name_delim_in  IN VARCHAR2
                             , inner_delim_in IN VARCHAR2
                              );
    
       PROCEDURE show_variations;
    
       /* Helper function for automated testing */
       FUNCTION nested_eq (list1_in    IN items_tt
                         , list2_in    IN items_tt
                         , nulls_eq_in IN BOOLEAN
                          )
          RETURN BOOLEAN;
    
    END parse;
    /
    
    CREATE OR REPLACE PACKAGE BODY parse
    IS
       FUNCTION string_to_list (string_in IN VARCHAR2, delim_in IN VARCHAR2)
          RETURN items_tt
       IS
          c_end_of_list   CONSTANT PLS_INTEGER := -99;
          l_item          maxvarchar2_t;
          l_startloc      PLS_INTEGER := 1;
          items_out       items_tt;
    
          PROCEDURE add_item (item_in IN VARCHAR2)
          IS
          BEGIN
             IF item_in = delim_in
             THEN
                /* We don't put delimiters into the collection. */
                NULL;
             ELSE
                items_out (items_out.COUNT + 1) := item_in;
             END IF;
          END;
    
          PROCEDURE get_next_item (string_in         IN     VARCHAR2
                                 , start_location_io IN OUT PLS_INTEGER
                                 , item_out             OUT VARCHAR2
                                  )
          IS
             l_loc   PLS_INTEGER;
          BEGIN
             l_loc := INSTR (string_in, delim_in, start_location_io);
    
             IF l_loc = start_location_io
             THEN
                /* A null item (two consecutive delimiters) */
                item_out := NULL;
             ELSIF l_loc = 0
             THEN
                /* We are at the last item in the list. */
                item_out := SUBSTR (string_in, start_location_io);
             ELSE
                /* Extract the element between the two positions. */
                item_out :=
                   SUBSTR (string_in
                         , start_location_io
                         , l_loc - start_location_io
                          );
             END IF;
    
             IF l_loc = 0
             THEN
                /* If the delimiter was not found, send back indication
                   that we are at the end of the list. */
    
                start_location_io := c_end_of_list;
             ELSE
                /* Move the starting point for the INSTR search forward. */
                start_location_io := l_loc + 1;
             END IF;
          END get_next_item;
       BEGIN
          IF string_in IS NULL OR delim_in IS NULL
          THEN
             /* Nothing to do except pass back the empty collection. */
             NULL;
          ELSE
             LOOP
                get_next_item (string_in, l_startloc, l_item);
                add_item (l_item);
                EXIT WHEN l_startloc = c_end_of_list;
             END LOOP;
          END IF;
    
          RETURN items_out;
       END string_to_list;
    
       FUNCTION string_to_list (string_in      IN VARCHAR2
                              , outer_delim_in IN VARCHAR2
                              , inner_delim_in IN VARCHAR2
                               )
          RETURN nested_items_tt
       IS
          l_elements   items_tt;
          l_return     nested_items_tt;
       BEGIN
          /* Separate out the different lists. */
          l_elements := string_to_list (string_in, outer_delim_in);
    
          /* For each list, parse out the separate items
             and add them to the end of the list of items
             for that list. */   
          FOR indx IN 1 .. l_elements.COUNT
          LOOP
             l_return (l_return.COUNT + 1) :=
                string_to_list (l_elements (indx), inner_delim_in);
          END LOOP;
    
          RETURN l_return;
       END string_to_list;
    
       FUNCTION string_to_list (string_in      IN VARCHAR2
                              , outer_delim_in IN VARCHAR2
                              , name_delim_in  IN VARCHAR2
                              , inner_delim_in IN VARCHAR2
                               )
          RETURN named_nested_items_tt
       IS
          c_name_position constant pls_integer := 1;
          c_items_position constant pls_integer := 2;
          l_elements          items_tt;
          l_name_and_values   items_tt;
          l_return            named_nested_items_tt;
       BEGIN
          /* Separate out the different lists. */
          l_elements := string_to_list (string_in, outer_delim_in);
    
          FOR indx IN 1 .. l_elements.COUNT
          LOOP
             /* Extract the name and the list of items that go with 
                the name. This collection always has just two elements:
                  index 1 - the name
                  index 2 - the list of values
             */
             l_name_and_values :=
                string_to_list (l_elements (indx), name_delim_in);
             /*
             Use the name as the index value for this list.
             */
             l_return (l_name_and_values (c_name_position)) :=
                string_to_list (l_name_and_values (c_items_position), inner_delim_in);
          END LOOP;
    
          RETURN l_return;
       END string_to_list;
    
       PROCEDURE display_list (string_in IN VARCHAR2
                             , delim_in  IN VARCHAR2:= ','
                              )
       IS
          l_items   items_tt;
       BEGIN
          DBMS_OUTPUT.put_line (
             'Parse "' || string_in || '" using "' || delim_in || '"'
          );
    
          l_items := string_to_list (string_in, delim_in);
    
          FOR indx IN 1 .. l_items.COUNT
          LOOP
             DBMS_OUTPUT.put_line ('> ' || indx || ' = ' || l_items (indx));
          END LOOP;
       END display_list;
    
       PROCEDURE display_list (string_in      IN VARCHAR2
                             , outer_delim_in IN VARCHAR2
                             , inner_delim_in IN VARCHAR2
                              )
       IS
          l_items   nested_items_tt;
       BEGIN
          DBMS_OUTPUT.put_line(   'Parse "'
                               || string_in
                               || '" using "'
                               || outer_delim_in
                               || '-'
                               || inner_delim_in
                               || '"');
          l_items := string_to_list (string_in, outer_delim_in, inner_delim_in);
    
    
          FOR outer_index IN 1 .. l_items.COUNT
          LOOP
             DBMS_OUTPUT.put_line(   'List '
                                  || outer_index
                                  || ' contains '
                                  || l_items (outer_index).COUNT
                                  || ' elements');
    
             FOR inner_index IN 1 .. l_items (outer_index).COUNT
             LOOP
                DBMS_OUTPUT.put_line(   '> Value '
                                     || inner_index
                                     || ' = '
                                     || l_items (outer_index) (inner_index));
             END LOOP;
          END LOOP;
       END display_list;
    
       PROCEDURE display_list (string_in      IN VARCHAR2
                             , outer_delim_in IN VARCHAR2
                             , name_delim_in  IN VARCHAR2
                             , inner_delim_in IN VARCHAR2
                              )
       IS
          l_items   named_nested_items_tt;
          l_index   maxvarchar2_t;
       BEGIN
          DBMS_OUTPUT.put_line(   'Parse "'
                               || string_in
                               || '" using "'
                               || outer_delim_in
                               || '-'
                               || name_delim_in
                               || '-'
                               || inner_delim_in
                               || '"');
          l_items :=
             string_to_list (string_in
                           , outer_delim_in
                           , name_delim_in
                           , inner_delim_in
                            );
    
          l_index := l_items.FIRST;
    
          WHILE (l_index IS NOT NULL)
          LOOP
             DBMS_OUTPUT.put_line(   'List "'
                                  || l_index
                                  || '" contains '
                                  || l_items (l_index).COUNT
                                  || ' elements');
    
             FOR inner_index IN 1 .. l_items (l_index).COUNT
             LOOP
                DBMS_OUTPUT.put_line(   '> Value '
                                     || inner_index
                                     || ' = '
                                     || l_items (l_index) (inner_index));
             END LOOP;
    
             l_index := l_items.NEXT (l_index);
          END LOOP;
       END display_list;
    
       PROCEDURE show_variations
       IS
          PROCEDURE show_header (title_in IN VARCHAR2)
          IS
          BEGIN
             DBMS_OUTPUT.put_line (RPAD ('=', 60, '='));
             DBMS_OUTPUT.put_line (title_in);
             DBMS_OUTPUT.put_line (RPAD ('=', 60, '='));
          END show_header;
       BEGIN
          show_header ('Single Delimiter Lists');
          display_list ('a,b,c');
          display_list ('a;b;c', ';');
          display_list ('a,,b,c');
          display_list (',,b,c,,');
    
          show_header ('Nested Lists');
          display_list ('a,b,c,d|1,2,3|x,y,z', '|', ',');
    
          show_header ('Named, Nested Lists');
          display_list ('letters:a,b,c,d|numbers:1,2,3|names:steven,george'
                      , '|'
                      , ':'
                      , ','
                       );
       END;
    
       FUNCTION nested_eq (list1_in    IN items_tt
                         , list2_in    IN items_tt
                         , nulls_eq_in IN BOOLEAN
                          )
          RETURN BOOLEAN
       IS
          l_return   BOOLEAN := list1_in.COUNT = list2_in.COUNT;
          l_index    PLS_INTEGER := 1;
       BEGIN
          WHILE (l_return AND l_index IS NOT NULL)
          LOOP
             l_return := list1_in (l_index) = list2_in (l_index);
             l_index := list1_in.NEXT (l_index);
          END LOOP;
    
          RETURN l_return;
       EXCEPTION
          WHEN NO_DATA_FOUND
          THEN
             RETURN FALSE;
       END nested_eq;
    END;
    /
    
    0 讨论(0)
  • 2020-11-27 03:44

    You can use Replace Function to replace comma easily. To Do this-

    The syntax for the REPLACE function in SQL Server (Transact-SQL) is:
    REPLACE( string, string_to_replace, replacement_string )

    Parameters or Arguments

    string : The source string from which a sequence of characters will be replaced by another set of characters.
    string_to_replace : The string that will be searched for in string1.
    replacement_string : The replacement string. All occurrences of string_to_replace will be replaced with replacement_string in string1.
    Note :

    The REPLACE function performs a replacement that is not case-sensitive. So all occurrences of string_to_replace will be replaced with replacement_string regardless of the case of string_to_replace or replacement_string

    For Example :
    SELECT REPLACE('Kapil,raj,chouhan', ',' , ' ') from DUAL;
    Result : Kapil raj chouhan

    SELECT REPLACE('I Live In India', ' ' , '-') from DUAL;
    Result : I-Live-In-India

    SELECT REPLACE('facebook.com', 'face' , 'friends') from DUAL;
    Result : friendsbook.com

    I Hope it will be usefull for you.

    0 讨论(0)
  • 2020-11-27 03:47

    Oracle provides the builtin function DBMS_UTILITY.COMMA_TO_TABLE.

    Unfortunately, this one doesn't work with numbers:

    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
    

    But with a little trick to prefix the elements with an 'x', it works:

    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 讨论(0)
提交回复
热议问题