2008-10-28 1 views
11

Как создать хранимую процедуру 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; 

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

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

ответ

25

Использование 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», который затем можно лечить, как и любую другую таблицу (так что присоединяется или, в этом case, subselects).

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

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

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

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

-1

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

Нечто подобное можно сделать с помощью PL/SQL, но быстрее передать коллекцию в процедуру как строку csv. Строка csv должна быть указана сначала в PL/SQL. – tuinstoel 2009-01-04 20:08:52

-1

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

+1

Мне нужно выполнить в процедуре plsql больше инструкций, чем «обновление». Для примера я упростил проблему. – 2008-10-28 10:30:33

0

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

См Asktom

1

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

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

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

+0

«нет прямого способа создания процедур с переменным числом параметров» ... Да, используйте CREATE TYPE xxx AS TABLE OFYYY, а затем используйте этот тип в качестве типа параметра. – ObiWanKenobi 2010-11-18 16:51:50

+0

Нет, это не прямое решение. В любом случае ваш метод является принятым ответом, датированным 2008 годом. – rics 2010-11-18 20:08:39

0

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

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

Great article by Mark A. Williams

Смежные вопросы