如何创建一个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功能兼容。
谢谢, 罗伯特
答案 0 :(得分:26)
使用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开发人员遇到这个问题。
答案 1 :(得分:2)
我找到了Mark A. Williams的以下文章,我认为这篇文章对这个帖子很有用。本文提供了一个使用关联数组将数组从C#传递到PL / SQL过程的一个很好的示例(TYPE myType IS TABLE OF mytable.row%TYPE INDEX BY PLS_INTEGER):
答案 2 :(得分:1)
我认为没有直接的方法来创建具有可变数量参数的过程。 但是,问题有一些,至少部分解决,here。
不幸的是,我没有.NET环境的经验。
答案 3 :(得分: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);
答案 4 :(得分:-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))
答案 5 :(得分:-1)
为什么它必须是存储过程?您可以以编程方式构建预准备语句。
答案 6 :(得分:-1)
AskTom网站上有一篇文章,展示了如何创建一个解析CSV字符串的函数,并在语句中使用它,其方式与给出的SQL Server示例类似。
请参阅Asktom