Search code examples
oracle-databasecollectionsplsqlsql-in

Using "IN" instead of "FOR" loop with a collection


I have a plsql procedure which takes an array of data and updates bunch of records, I am able to do this with a for loop. I could really use some help figuring out to do this without a loop.

Package spec and body:

create or replace PACKAGE ARRAY_EXAMPLE AS
  type arrtype is table of test_table.name%TYPE index by pls_integer;

  PROCEDURE PROCESS_ARRAY( stringArrayIn IN arrtype
                         , p_city           varchar2
                         , p_phone          number);
END;
/

create or replace PACKAGE BODY ARRAY_EXAMPLE AS

  PROCEDURE PROCESS_ARRAY( stringArrayIn IN arrtype
                         , p_city           varchar2
                         , p_phone          number) IS   
  BEGIN
   FOR i IN 1..stringArrayIn.Count
   LOOP
      update test_table t
         set t.city = p_city 
       where t.name = stringArrayIn(i)
         and t.phone = p_phone;
   END LOOP;
  END;
END;
/

What I want to have:

create or replace PACKAGE BODY ARRAY_EXAMPLE AS

  PROCEDURE PROCESS_ARRAY( stringArrayIn IN arrtype
                           , p_city           varchar2
                           , p_phone          number) IS   
  BEGIN
     update test_table t
        set t.city = p_city
      where t.phone = p_phone
        and t.name in (stringArrayIn);
  END;
END;

I get error when I try the above, please help. thank you very much in advance.


Solution

  • You will need to define the collection in SQL rather than PL/SQL:

    create type arrtype is table of VARCHAR2(100);
    
    create or replace PACKAGE BODY ARRAY_EXAMPLE AS
      PROCEDURE PROCESS_ARRAY(
        stringArrayIn IN arrtype
      , p_city        IN varchar2
      , p_phone       IN number
      )
      IS 
      BEGIN
        update test_table t
        set    t.city  = p_city
        where  t.phone = p_phone
        and    t.name  MEMBER OF stringArrayIn
      END;
    END;
    /
    

    Update

    Initialise an array on instantiation:

    DECLARE
      t_names ARRTYPE := t_names( 'Alice', 'Bob', 'Charlie' );
    BEGIN
      ARRAY_EXAMPLE.PROCESS_ARRAY(
        t_names,
        'New York City',
        '555-2368'
      );
    END;
    /
    

    Populate an array later:

    DECLARE
      t_names ARRTYPE;
    BEGIN
      t_names := ARRTYPE();
      t_names.EXTEND(3);
      t_names(1) := 'Alice';
      t_names(2) := 'Bob';
      t_names(3) := 'Charlie';
    
      ARRAY_EXAMPLE.PROCESS_ARRAY(
        t_names,
        'New York City',
        '555-2368'
      );
    END;
    /
    

    You can see from the second example that the array elements are still indexed.