pass integer array to oracle procedure by c#

前端 未结 2 1947
感动是毒
感动是毒 2020-12-18 16:09

I want to pass an integer array to a stored procedure via c#. the procedure works via sql developer but in c# it doesn\'t work. this is my code but i got stuck by the

2条回答
  •  感动是毒
    2020-12-18 17:15

    Your type:

    create or replace TYPE INNUMARRAY AS TABLE OF INTEGER;
    

    is a collection defined in the SQL scope.

    Your passed argument:

    p_strings.CollectionType = OracleCollectionType.PLSQLAssociativeArray;
    p_strings.Value = new int[5]{1,2,3,4,5};
    

    is an associative array which can only be defined in a PL/SQL scope (i.e. in a package or within a PL/SQL block) and cannot be used in an SQL scope.

    They are two different and incompatible data types.

    Instead, you can create an associative array type in a package and then manually extract each value from the associative array into a collection that can be used in the SQL scope:

    CREATE PACKAGE vehicles_pkg IS
      TYPE INNUMASSOCARRAY IS TABLE OF INTEGER INDEX BY BINARY_INTEGER;
    
      PROCEDURE v1
      (
        VehicleGroupID_Array IN INNUMASSOCARRAY
      );
    END;
    /
    
    CREATE PACKAGE BODY vehicles_pkg IS
      PROCEDURE v1
      (
        VehicleGroupID_Array IN INNUMASSOCARRAY
      )
      IS
        p_recordset SYS_REFCURSOR;
        p_array     INNUMARRAY := INNUMARRAY();
        i           BINARY_INTEGER;
      BEGIN
        i := VehicleGroupID_Array.FIRST;
        WHILE i IS NOT NULL LOOP
          p_array.EXTEND;
          p_array( p_array.COUNT ) := VehicleGroupID_Array(i);
          i := VehicleGroupID_Array.NEXT(i);
        END LOOP;
    
        -- Rest of your procedure using p_array instead of the associative array.
      END;
    END;
    /
    

    can I define the associative array type outside of package? I want them to be standalone.

    No, but you can define a package just containing the type:

    CREATE PACKAGE vehicles_pkg IS
      TYPE INNUMASSOCARRAY IS TABLE OF INTEGER INDEX BY BINARY_INTEGER;
    END;
    /
    
    CREATE PROCEDURE v1
    (
      VehicleGroupID_Array IN vehicles_pkg.INNUMASSOCARRAY
    )
    IS
      p_recordset SYS_REFCURSOR;
      p_array     INNUMARRAY := INNUMARRAY();
      i           BINARY_INTEGER;
    BEGIN
      i := VehicleGroupID_Array.FIRST;
      WHILE i IS NOT NULL LOOP
        p_array.EXTEND;
        p_array( p_array.COUNT ) := VehicleGroupID_Array(i);
        i := VehicleGroupID_Array.NEXT(i);
      END LOOP;
    
      -- Rest of your procedure using p_array instead of the associative array.
    END;
    /
    

    Or, better, create some generically named types and a function in the package to translate from an associative array to a collection and then reuse them in your procedures:

    SQL Fiddle

    Oracle 11g R2 Schema Setup:

    CREATE TYPE IntList AS TABLE OF INTEGER
    /
    
    CREATE PACKAGE tools IS
      TYPE IntMap IS TABLE OF INTEGER INDEX BY BINARY_INTEGER;
    
      FUNCTION IntMapToList(
        i_map IntMap
      ) RETURN IntList;
    END;
    /
    
    CREATE PACKAGE BODY tools IS
      FUNCTION IntMapToList(
        i_map IntMap
      ) RETURN IntList
      IS
        o_list IntList := IntList();
        i      BINARY_INTEGER;
      BEGIN
        IF i_map IS NOT NULL THEN
          i := o_list.FIRST;
          WHILE i IS NOT NULL LOOP
            o_list.EXTEND;
            o_list( o_list.COUNT ) := i_map( i );
            i := i_map.NEXT( i );
          END LOOP;
        END IF;
        RETURN o_list;
      END;
    END;
    /
    
    CREATE PROCEDURE v1
    (
      VehicleGroupID_Array IN tools.IntMap
    )
    IS
      p_recordset SYS_REFCURSOR;
      p_array     IntList := tools.IntMapToList( VehicleGroupID_Array );
      i           BINARY_INTEGER;
    BEGIN
      -- Rest of your procedure using p_array instead of the associative array.
      NULL;
    END;
    /
    

提交回复
热议问题