Хранимая процедура Oracle с параметрами для предложения IN - PullRequest
12 голосов
/ 28 октября 2008

Как мне создать хранимую процедуру Oracle, которая принимает переменное число значений параметров, используемых для подачи предложения IN?

Это то, чего я пытаюсь достичь. Я не знаю, как объявить в PLSQL для передачи списка переменных первичных ключей строк, которые я хочу обновить.

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;

Кроме того, я хотел бы вызвать эту процедуру из C #, поэтому она должна быть совместима с возможностями .NET.

Спасибо, Роберт

Ответы [ 7 ]

26 голосов
/ 28 октября 2008

Использование CSV, вероятно, самый простой способ, при условии, что вы можете быть на 100% уверены, что ваши элементы сами не будут содержать строки.

Альтернативный и, возможно, более надежный способ сделать это - создать пользовательский тип в виде таблицы строк. Предположим, что ваши строки никогда не были длиннее 100 символов, тогда вы могли бы иметь:

CREATE TYPE string_table AS TABLE OF varchar2(100);

Затем вы можете передать переменную этого типа в вашу хранимую процедуру и напрямую ссылаться на нее. В твоем случае примерно так:

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

Функция table() превращает ваш пользовательский тип в таблицу с одним столбцом "COLUMN_VALUE", которую вы затем можете обрабатывать как любую другую таблицу (то же самое можно сделать с присоединениями или, в этом случае, с помощью выбора).

Прелесть этого в том, что Oracle создаст для вас конструктор, поэтому при вызове хранимой процедуры вы можете просто написать:

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

Я предполагаю, что вы можете обработать эту команду программно из C #.

Кроме того, в моей компании у нас есть ряд этих пользовательских типов, определенных как стандартные для списков строк, двойных чисел, целых и т. Д. Мы также используем Oracle JPublisher , чтобы иметь возможность напрямую сопоставлять эти типы с соответствующими объектами Java. Я быстро осмотрелся вокруг, но я не увидел прямых эквивалентов для C #. Просто подумал, что упомяну об этом на случай, если разработчики Java столкнутся с этим вопросом.

2 голосов
/ 11 декабря 2009

Я нашел следующую статью Марка А. Уильямса, которая, по моему мнению, была бы полезным дополнением к этой теме. В статье приводится хороший пример передачи массивов из C # в PL / SQL-процессы с использованием ассоциативных массивов (TYPE myType IS TABLE OF mytable.row% TYPE INDEX BY PLS_INTEGER):

Отличная статья Марка А. Уильямса

1 голос
/ 28 октября 2008

Я думаю, что нет прямого способа создания процедур с переменным количеством параметров. Однако есть некоторые, по крайней мере частичные решения проблемы, описанные здесь .

  1. При некоторых типичных типах вызовов может помочь перегрузка процедуры.
  2. Если существует верхний предел количества параметров (и их тип также известен заранее), значения параметров по умолчанию могут помочь.
  3. Наилучшим вариантом может быть использование переменных курсора, которые являются указателями на курсоры базы данных.

К сожалению, у меня нет опыта работы со средами .NET.

0 голосов
/ 05 августа 2009

Почему бы просто не использовать длинный список параметров и загрузить значения в конструктор таблицы? Вот SQL / PSM для этого трюка

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);
0 голосов
/ 28 октября 2008

На веб-сайте AskTom есть статья, в которой показано, как создать функцию для анализа строки CSV и использовать ее в своем выражении аналогично приведенному примеру SQL Server.

См. Аскомтом

0 голосов
/ 28 октября 2008

Почему это должна быть хранимая процедура? Вы можете создать подготовленный оператор программно.

0 голосов
/ 28 октября 2008

Я не делал этого для Oracle, но с SQL Server вы можете использовать функцию для преобразования строки CSV в таблицу, которую затем можно использовать в предложении IN. Было бы просто переписать это для Oracle (я думаю!)

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

Затем вы можете передать строку CSV (например, «0001,0002,0003») и сделать что-то вроде

UPDATE table1 SET 
       col1 = col1 - value 
WHERE id in (SELECT * FROM csvToInt(@myParam)) 
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...