Pergunta

Como posso criar um procedimento armazenado Oracle que aceita um número variável de valores dos parâmetros usados ??para alimentar uma cláusula IN?

Este é o que eu estou tentando alcançar. Eu não sei como declarar em PLSQL para passar uma variável lista de chaves primárias das linhas que deseja atualizar.

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;

Além disso, eu gostaria de chamar este procedimento a partir do C #, por isso deve ser compatível com as capacidades .NET.

Obrigado, Robert

Foi útil?

Solução

Usando CSV é provavelmente a maneira mais simples, supondo que você pode ser 100% certo de que os seus elementos não próprios contêm strings.

Uma alternativa, e provavelmente mais robusta, maneira de fazer isso é criar um tipo personalizado como uma tabela de strings. Supondo suas cordas nunca foram mais de 100 caracteres, então você poderia ter:

CREATE TYPE string_table AS TABLE OF varchar2(100);

Você pode então passar uma variável deste tipo em seu procedimento armazenado e referenciá-lo diretamente. No seu caso, algo como isto:

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

A função table() transforma seu tipo personalizado em uma tabela com uma única coluna "column_value", que você pode então tratar como qualquer outra tabela (assim como junta ou, neste caso, subselects).

A beleza disto é que a Oracle irá criar um construtor para você, então ao chamar o procedimento armazenado, você pode simplesmente escrever:

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

Estou assumindo que você pode lidar com a construção de este comando programaticamente a partir de C #.

Como um aparte, na minha empresa, temos um número desses tipos personalizados definidos como padrão para listas de cordas, duplos, ints e assim por diante. Nós também fazer uso de a Oracle JPublisher para ser capaz de mapear diretamente desses tipos em correspondente objetos Java. Eu tive uma volta rápida olhada, mas eu não podia ver quaisquer equivalentes diretos para C #. Só pensei que eu iria falar dele em caso devs Java se deparar com esta questão.

Outras dicas

Eu encontrei o seguinte artigo de Mark A. Williams, que eu pensei que seria uma adição útil para esta discussão. O artigo dá um bom exemplo de passar matrizes de C # para PL / SQL procs usando arrays associativos (TIPO myType É TABELA DE mytable.row% tipo de Índice pelo PLS_INTEGER):

Excelente artigo de Mark A. Williams

Eu acho que não há nenhuma maneira direta para criar procedimentos com número variável de parâmetros. No entanto, existem alguns, pelo menos soluções parciais para o problema, descrito aqui .

  1. Se há alguns típico procedimento tipos de chamada sobrecarga ajuda Maio.
  2. Se houver um limite superior no número de parâmetros (e seu tipo também é conhecido com antecedência), os valores padrão de parâmetros podem ajudar.
  3. A melhor opção é talvez o uso de variáveis ??de cursor que são ponteiros para cursores de banco de dados.

Infelizmente eu não tenho nenhuma experiência com .NET ambientes.

Por que não usar uma lista de parâmetros de comprimento e carregar os valores em um construtor mesa? Aqui está o SQL / PSM para este truque

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 que tem de ser um procedimento armazenado? Você poderia construir-se uma declaração preparada por meio de programação.

Eu não fiz isso para Oracle, mas com SQL Server você pode usar uma função para converter uma string CSV em uma tabela, que pode então ser usada em uma cláusula IN. Deve ser claro e direto para re-escrever este for Oracle (eu acho!)

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

Em seguida, você pode passar uma cadeia de CSV (por exemplo '0001,0002,0003') e fazer algo como

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

Há um artigo no site AskTom que mostra como criar uma função para analisar a cadeia CSV e usar isso em sua declaração de uma maneira semelhante ao exemplo SQL Server dada.

Veja AskTom

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top