Хранимая процедура Oracle с параметрами для предложения IN
-
04-07-2019 - |
Вопрос
Как я могу создать хранимую процедуру 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).:
Я думаю, что нет прямого способа создавать процедуры с переменным количеством параметров.Однако существуют некоторые, по крайней мере частичные решения описанной проблемы здесь.
- Если существуют какие-то типичные типы вызовов, перегрузка процедур может помочь.
- Если существует верхний предел количества параметров (и их тип также известен заранее), могут помочь значения параметров по умолчанию.
- Возможно, лучшим вариантом является использование переменных курсора, которые являются указателями на курсоры базы данных.
К сожалению, у меня нет опыта работы с .Сетевыми средами.
Почему бы просто не использовать длинный список параметров и не загрузить значения в табличный конструктор?Вот 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.
Видишь Асктом