c# - 从 C# 中的 PL/SQL 匿名 block 返回游标

标签 c# sql oracle plsql odp.net

我正在努力将现有应用程序从 SQL Server 转换到 Oracle,但遇到了障碍。我正在尝试将匿名 block 作为动态 SQL 执行并返回结果集。但是,我尝试过的任何事情似乎都无法返回任何值。由于设计限制,存储过程不可用。

我的查询定义为:

DECLARE type id_array IS TABLE OF number;
t_Ids id_array;
BEGIN
UPDATE CSM_RECORDS SET MIGRATION_STATE = 1, LAST_UPDATE = CURRENT_DATE
WHERE OBJECT_UID IN 
(SELECT OBJECT_UID 
FROM CSM_RECORDS obj 
WHERE MIGRATION_STATE = 0
AND ROWNUM <= :BatchSize)
AND (:BatchName IS NULL OR obj.BATCH_NAME = :BatchName)
RETURNING OBJECT_UID BULK COLLECT INTO t_Ids;

OPEN rcursor FOR SELECT * FROM CSM_RECORDS;-- WHERE OBJECT_UID IN (t_Ids);
END;

你可以看到我已经注释掉了游标上的 WHERE 子句,试图让任何返回。

在 C# 方面,我有:

OracleCommand getNextNodesC = new OracleCommand(SQL_AS_SHOWN_ABOVE, conn);
getNextNodesC.BindByName = true;

OracleParameter batchSizeP = new OracleParameter("BatchSize", OracleDbType.Int32);
batchSizeP.Value = batchSize;

getNextNodesC.Parameters.Add(batchSizeP);

OracleParameter batchNameP = new OracleParameter("BatchName", OracleDbType.Varchar2);
batchNameP.Value = batchName;

getNextNodesC.Parameters.Add(batchNameP);


OracleParameter returnCursor = new OracleParameter("rcursor", OracleDbType.RefCursor);
returnCursor.Direction = ParameterDirection.Output;
getNextNodesC.Parameters.Add(returnCursor);

getNextNodesC.ExecuteNonQuery();

return ((Oracle.ManagedDataAccess.Types.OracleRefCursor)returnCursor.Value).GetDataReader();

最终目标是我可以使用的 DbDataReader,但在上面的代码中,returnCursor.Value 似乎仍为空。我尝试了 OutputReturnValue 参数以及 ExecuteNonQuery()ExecuteReader() 的各种组合,但没有有用。

任何指针都将不胜感激,但实际上可以完成我正在寻找的代码示例将是非常壮观的。

最佳答案

TLDR:您的光标绑定(bind)变量上缺少冒号:

OPEN :rcursor FOR SELECT * FROM CSM_RECORDS;-- WHERE OBJECT_UID IN (t_Ids);

完整答案: 您可能知道,在 oracle 中有 pl/sql 上下文(您的匿名 block )和 SQLplus 上下文。这是一个带有 SQLplus 变量的 block ,一个带有相关绑定(bind)变量的 block ,最后是一个 SQLplus 打印:

var rcursor refcursor
var fromDate varchar2(50)
var toDate varchar2(50)
exec :fromDate := '1-mar-2014';
exec :toDate := '1-apr-2014';

begin
  open :rcursor for
    SELECT
     trunc(to_date(:fromDate,'dd-mon-yyyy')) + NUMTODSINTERVAL(n,'day') AS Full_Date
    FROM (
    select (level-1) n
    from dual
    connect by level-1 <= trunc(to_date(:toDate,'dd-mon-yyyy')) - trunc(to_date(:fromDate,'dd-mon-yyyy'))
   )
  ;
end;
/
print rcursor

在 .net 中执行 block 时,ODP.net 负责在 SQLplus 级别完成的准备工作。这是从 .net 执行的相同 block (作为 nunit 测试):

[Test]
public void RefCursorFromBatch()
{
  OracleCommand cmd = new OracleCommand();
  cmd.CommandText = @"
  begin
    open :rcursor for
      SELECT
       trunc(to_date(:fromDate,'dd-mon-yyyy')) + NUMTODSINTERVAL(n,'day') AS Full_Date
      FROM (
      select (level-1) n
      from dual
      connect by level-1 <= trunc(to_date(:toDate,'dd-mon-yyyy')) - trunc(to_date(:fromDate,'dd-mon-yyyy'))
     )
    ;
  end;";
  cmd.BindByName = true;
  cmd.Parameters.Add("fromDate", OracleDbType.Date).Value = DateTime.Today.AddDays(-30);
  cmd.Parameters.Add("toDate", OracleDbType.Date).Value = DateTime.Today;
  cmd.Parameters.Add("rcursor", OracleDbType.RefCursor).Direction = ParameterDirection.Output;

  using (cmd.Connection = new OracleConnection("..."))
  {
    cmd.Connection.Open();
    var reader = cmd.ExecuteReader();

    OracleDataAdapter da = new OracleDataAdapter(cmd);
    DataTable dt = new DataTable();
    da.Fill(dt);

    Assert.Greater(dt.Rows.Count, 0);

  }
}

您可以在此处阅读更多信息:http://www.brothersincode.com/post/executing-SQL-Plus-Batches-from-Net.aspx

关于c# - 从 C# 中的 PL/SQL 匿名 block 返回游标,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/22821112/

相关文章:

c# - 表达式树作为用户定义查询引擎的基础(使用 EAV)?

c# - 服务器/客户端套接字连接

php - 给出警告 : mysql_result() expects parameter 1 to be resource, bool 值

sql - Oracle 自定义排序

java - 使用 Spring Boot 在两个或多个 (Oracle) 数据库上使用多个存储过程?

sql - ADD_MONTHS函数在Oracle中未返回正确的日期

c# - 为值对象序列化自定义 NewtonSoft.Json

c# - 使用 C# 2010 连接到 SQL Server 2008 的小问题

sql - oracle中的错误/异常处理

MySQL:如何将结果限制为另一个字段的最大值?