Хранимая процедура Oracle с параметрами для предложения IN

StackOverflow https://stackoverflow.com/questions/242771

Вопрос

Как я могу создать хранимую процедуру 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 #, поэтому она должна быть совместима с .СЕТЕВЫЕ возможности.

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

Это было полезно?

Решение

Использование 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 JP publisher - издатель чтобы иметь возможность напрямую сопоставлять эти типы с соответствующими объектами Java.Я быстро осмотрелся, но не увидел никаких прямых эквивалентов для C #.Просто подумал, что стоит упомянуть об этом на случай, если разработчики Java столкнутся с этим вопросом.

Другие советы

Я нашел следующую статью Марка А.Уильямс, который, как я подумал, был бы полезным дополнением к этой теме.В статье приведен хороший пример передачи массивов из C # в процедуры PL / SQL с использованием ассоциативных массивов (ТИП MyType - ТАБЛИЦА ИНДЕКСА mytable.row% ОТ PLS_INTEGER).:

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

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

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

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

Почему бы просто не использовать длинный список параметров и не загрузить значения в табличный конструктор?Вот 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);

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

Я не делал этого для 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)) 

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

Видишь Асктом

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top