Domanda

Come posso creare una procedura memorizzata Oracle che accetta un numero variabile di valori di parametro utilizzati per alimentare una clausola IN?

Questo è ciò che sto cercando di ottenere. Non so come dichiarare in PLSQL per il passaggio di un elenco variabile di chiavi primarie delle righe che voglio aggiornare.

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;

Inoltre, vorrei chiamare questa procedura da C #, quindi deve essere compatibile con le funzionalità .NET.

Grazie, Robert

È stato utile?

Soluzione

L'uso di CSV è probabilmente il modo più semplice, supponendo che tu possa essere sicuro al 100% che i tuoi elementi non contengano stringhe.

Un modo alternativo, e probabilmente più robusto, per farlo è quello di creare un tipo personalizzato come una tabella di stringhe. Supponiamo che le tue stringhe non siano mai più lunghe di 100 caratteri, quindi potresti avere:

CREATE TYPE string_table AS TABLE OF varchar2(100);

È quindi possibile passare una variabile di questo tipo nella procedura memorizzata e fare riferimento direttamente a essa. Nel tuo caso, qualcosa del genere:

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 funzione table () trasforma il tuo tipo personalizzato in una tabella con una singola colonna " COLUMN_VALUE " ;, che puoi quindi trattare come qualsiasi altra tabella (quindi fai join o, in questo caso, subselect).

Il bello di questo è che Oracle creerà un costruttore per te, quindi quando chiami la tua procedura memorizzata puoi semplicemente scrivere:

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

Suppongo che tu possa gestire la creazione di questo comando a livello di codice da C #.

A parte questo, nella mia azienda abbiamo un certo numero di questi tipi personalizzati definiti come standard per elenchi di stringhe, doppi, ints e così via. Utilizziamo anche Oracle JPublisher per essere in grado di mappare direttamente da questi tipi nei corrispondenti oggetti Java. Ho dato una rapida occhiata in giro ma non sono riuscito a vedere alcun equivalente diretto per C #. Ho pensato di menzionarlo nel caso in cui gli sviluppatori Java incontrassero questa domanda.

Altri suggerimenti

Ho trovato il seguente articolo di Mark A. Williams che pensavo potesse essere un'utile aggiunta a questa discussione. L'articolo fornisce un buon esempio del passaggio di matrici da C # a proc PL / SQL mediante matrici associative (TYPE myType IS TABLE OF mytable.row% INDICE TIPO DI PLS_INTEGER):

Grande articolo di Mark A. Williams

Penso che non esista un modo diretto per creare procedure con un numero variabile di parametri. Tuttavia ci sono alcune, almeno parziali soluzioni al problema, descritte qui .

  1. Se ci sono alcuni tipi tipici di chiamata, il sovraccarico della procedura può aiutare.
  2. Se esiste un limite superiore nel numero di parametri (e il loro tipo è noto anche in anticipo), possono essere utili i valori predefiniti dei parametri.
  3. L'opzione migliore è forse l'uso delle variabili del cursore che sono puntatori ai cursori del database.

Sfortunatamente non ho esperienza con gli ambienti .NET.

Perché non usare solo un lungo elenco di parametri e caricare i valori in un costruttore di tabelle? Ecco l'SQL / PSM per questo trucco

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);

Perché deve essere una procedura memorizzata? È possibile creare un'istruzione preparata a livello di programmazione.

Non l'ho fatto per Oracle, ma con SQL Server è possibile utilizzare una funzione per convertire una stringa CSV in una tabella, che può quindi essere utilizzata in una clausola IN. Dovrebbe essere semplice riscriverlo per Oracle (penso!)

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

Quindi puoi passare una stringa CSV (ad es. "0001.0002.0003") e fare qualcosa del genere

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

Esiste un articolo sul sito Web AskTom che mostra come creare una funzione per analizzare la stringa CSV e utilizzarla nell'istruzione in modo simile all'esempio di SQL Server fornito.

Vedi Asktom

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top