Pregunta

¿Cómo puedo crear un procedimiento almacenado de Oracle que acepte un número variable de valores de parámetros utilizados para alimentar una cláusula IN?

Esto es lo que estoy tratando de lograr. No sé cómo declarar en PLSQL para pasar una lista variable de claves primarias de las filas que quiero actualizar.

FUNCTION EXECUTE_UPDATE
  ( <parameter_list>
   value IN int)
  RETURN  int IS
BEGIN 
    [...other statements...]
    update table1 set col1 = col1 - value where id in (<parameter_list>) 

    RETURN SQL%ROWCOUNT ;
END;

Además, me gustaría llamar a este procedimiento desde C #, por lo que debe ser compatible con las capacidades de .NET.

Gracias, Robert

¿Fue útil?

Solución

El uso de CSV es probablemente la forma más sencilla, asumiendo que puede estar 100% seguro de que sus elementos no contendrán cadenas.

Una forma alternativa, y probablemente más robusta, de hacer esto es crear un tipo personalizado como una tabla de cadenas. Suponiendo que sus cadenas nunca tuvieran más de 100 caracteres, podría tener:

CREATE TYPE string_table AS TABLE OF varchar2(100);

Luego puede pasar una variable de este tipo a su procedimiento almacenado y hacer referencia directamente. En tu caso, algo como esto:

FUNCTION EXECUTE_UPDATE(
    identifierList string_table,
    value int)
RETURN int
IS
BEGIN

    [...other stuff...]

    update table1 set col1 = col1 - value 
    where id in (select column_value from table(identifierList));

    RETURN SQL%ROWCOUNT;

END

La función table () convierte su tipo personalizado en una tabla con una sola columna " COLUMN_VALUE " ;, que luego puede tratar como cualquier otra tabla (así que haga combinaciones o, en este caso, subselecciones).

La belleza de esto es que Oracle creará un constructor para usted, de modo que cuando llame a su procedimiento almacenado, simplemente puede escribir:

execute_update(string_table('foo','bar','baz'), 32);

Supongo que puedes manejar la creación de este comando mediante programación desde C #.

Aparte de esto, en mi empresa tenemos varios de estos tipos personalizados definidos como estándar para listas de cadenas, dobles, ints, etc. También utilizamos Oracle JPublisher para poder mapear directamente desde estos tipos en objetos Java correspondientes. Eché un vistazo rápido a mi alrededor pero no pude ver ningún equivalente directo para C #. Pensé en mencionarlo en caso de que los desarrolladores de Java se encontraran con esta pregunta.

Otros consejos

Encontré el siguiente artículo de Mark A. Williams, que pensé que sería una adición útil a este hilo. El artículo proporciona un buen ejemplo de cómo pasar matrices de C # a procs PL / SQL usando matrices asociativas (TYPE myType ES TABLA DE mytable.row% TYPE INDEX BY PLS_INTEGER):

Gran artículo de Mark A. Williams

Creo que no hay una forma directa de crear procedimientos con un número variable de parámetros. Sin embargo, hay algunas, al menos soluciones parciales al problema, descritas en aquí .

  1. Si hay algunos tipos típicos de llamadas, el procedimiento de sobrecarga puede ayudar.
  2. Si hay un límite superior en el número de parámetros (y su tipo también se conoce de antemano), los valores predeterminados de los parámetros pueden ayudar.
  3. La mejor opción es tal vez el uso de variables de cursor, que son punteros a los cursores de base de datos.

Lamentablemente no tengo experiencia con los entornos .NET.

¿Por qué no solo usar una larga lista de parámetros y cargar los valores en un constructor de tablas? Aquí está el SQL / PSM para este truco

UPDATE Foobar
   SET x = 42
 WHERE Foobar.keycol
      IN (SELECT X.parm
            FROM (VALUES (in_p01), (in_p02), .., (in_p99)) X(parm)
           WHERE X.parm IS NOT NULL);

¿Por qué tiene que ser un procedimiento almacenado? Podrías construir una declaración preparada programáticamente.

No lo he hecho para Oracle, pero con SQL Server puede usar una función para convertir una cadena CSV en una tabla, que luego se puede usar en una cláusula IN. Debería ser sencillo volver a escribir esto para Oracle (¡creo!)

CREATE Function dbo.CsvToInt ( @Array varchar(1000)) 
returns @IntTable table 
    (IntValue nvarchar(100))
AS
begin

    declare @separator char(1)
    set @separator = ','

    declare @separator_position int 
    declare @array_value varchar(1000) 

    set @array = @array + ','

    while patindex('%,%' , @array) <> 0 
    begin

      select @separator_position =  patindex('%,%' , @array)
      select @array_value = left(@array, @separator_position - 1)

        Insert @IntTable
        Values (Cast(@array_value as nvarchar))

      select @array = stuff(@array, 1, @separator_position, '')
    end

    return
end

Luego puedes pasar una cadena CSV (por ejemplo, '0001,0002,0003') y hacer algo como

UPDATE table1 SET 
       col1 = col1 - value 
WHERE id in (SELECT * FROM csvToInt(@myParam)) 

Hay un artículo en el sitio web de AskTom que muestra cómo crear una función para analizar la cadena CSV y usar esto en su declaración de manera similar al ejemplo de SQL Server dado.

Consulte Asktom

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top