Oracle使用带有多个值的IN子句对SQL参数化了SQL

时间:2018-07-31 14:49:45

标签: oracle plsql

我有一个使用IN子句的参数化SQL语句,以便通过一个查询更新多个记录。它是一个整数字段,即RID(记录ID),用于进行更新。如果仅传递一个RID,则可以使用,但如果传递多个值,则会得到Error: ORA-01722: invalid number

这是代码:

sbQuery.Append("update EXC_LOG set supv_emp_id=:userId, status=:exceptionStatus, supv_comments=:exceptionComment ");
sbQuery.Append("where RID in (:rid)");
ctx.Database.ExecuteSqlCommand(sbQuery.ToString(),
                                new OracleParameter("userId", UserId),
                                new OracleParameter("exceptionStatus", exceptionStatus),
                                new OracleParameter("exceptionComment", comment),
                                new OracleParameter("rid", rid));

如果我传递一个值RID,它可以工作,但是如果我传递多个逗号分隔(例如:1234,5566,8899),则会收到无效数字错误。

使用参数时如何传递多个整数值?

1 个答案:

答案 0 :(得分:2)

您正在将单个字符串参数传递给IN()。如果该数字恰好包含一个数字,那么您实际上是在做:

where RID in ('12345')

,由于您的RID列为数字,因此将进行隐式转换,处理方式为:

where RID in (to_number('12345'))

这很好。但是在单个字符串参数中包含多个值,您实际上是在尝试这样做:

where RID in (to_number('12345,5566,8899'))

to_number('12345,5566,8899')将抛出ORA-01722:无效的数字。

有多种方法可以将定界的字符串解包为单个值,但是一种简单的方法是将它们视为XPath序列,并通过XMLTable调用进行放置:

sbQuery.Append("where RID in (select RID from XMLTable(:rid columns RID number path '.'))");

作为该方法的演示,首先XMLTable调用如何使用SQL * Plus绑定变量扩展字符串:

var rid varchar2(30);

exec :rd := '12345,5566,8899';

select RID from XMLTable('12345,5566,8899' columns RID number path '.');

       RID
----------
     12345
      5566
      8899

,然后在针对虚拟表的虚拟查询中:

with EXC_LOG (RID, SUPV_EMP_ID, STATUS, SUPV_COMMENT) as (
            select 12345, 123, 'OK', 'Blah blah' from dual
  union all select 8899, 234, 'Failed', 'Some comment' from dual
  union all select 99999, 456, 'Active', 'Workign on it' from dual
)
select *
from EXC_LOG
where RID in (select RID from XMLTable('12345,5566,8899' columns RID number path '.'));

       RID SUPV_EMP_ID STATUS SUPV_COMMENT 
---------- ----------- ------ -------------
     12345         123 OK     Blah blah    
      8899         234 Failed Some comment 

您的代码将使用相同的过滤器进行更新而不是选择。