Хранимая процедура Oracle с параметрами для предложения IN
Как создать хранимую процедуру 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;
Кроме того, я хотел бы вызвать эту процедуру из С#, поэтому она должна быть совместима с возможностями .NET.
Спасибо,
Роберт
Ответы
Ответ 1
Использование 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);
Я предполагаю, что вы можете обрабатывать эту команду программно из С#.
В стороне, в моей компании, у нас есть несколько таких пользовательских типов, которые определены как стандартные для списков строк, парных, int и т.д. Мы также используем Oracle JPublisher, чтобы иметь возможность напрямую сопоставлять эти типы с соответствующими объектами Java. Я быстро осмотрелся, но я не видел прямых эквивалентов для С#. Просто подумал, что я упомянул об этом, если бы разработчики Java столкнулись с этим вопросом.
Ответ 2
Я нашел следующую статью Марка А. Уильямса, которая, как я думал, станет полезным дополнением к этой теме. В статье приведен хороший пример передачи массивов из С# в PL/SQL-процессы с использованием ассоциативных массивов (TYPE myType IS TABLE OF mytable.row% TYPE INDEX BY PLS_INTEGER):
Отличная статья Марка А. Уильямса
Ответ 3
Я думаю, что нет прямого способа создания процедур с переменным числом параметров.
Однако есть некоторые, по крайней мере частичные решения проблемы, описанные здесь здесь.
- Если есть некоторые типичные типы вызовов, может помочь перегрузка процедур.
- Если есть верхний предел в числе параметров (и их тип также известен заранее), значения по умолчанию могут помочь.
- Лучшим вариантом может быть использование переменных курсора, которые являются указателями на курсоры базы данных.
К сожалению, у меня нет опыта работы с средами .NET.
Ответ 4
На веб-сайте AskTom есть статья, в которой показано, как создать функцию для синтаксического анализа строки CSV и использовать ее в своем заявлении аналогично приведенному примеру SQL Server.
См. Asktom
Ответ 5
Почему бы просто не использовать длинный список параметров и не загружать значения в конструктор таблицы? Вот 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);
Ответ 6
Я не делал этого для 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))
Ответ 7
Почему это должна быть хранимая процедура? Вы можете создать подготовленное выражение программным способом.