从 SSIS 上的脚本任务执行时,Oracle 过程不返回结果

Oracle procedure is not returning results when executing from script task on SSIS

我正在执行 Oracle 过程,它具有三个 OUTPUT 参数并且 returns 结果为 table 类型变量。

这里的限制是,我不应该使用 ODBC、MSDAORA 提供程序来调用该程序。所以我打算使用 Oracle OLEDB 提供程序。

我能够成功执行程序,但是当我检查时(dr.Read())它没有 returning 任何记录。但我知道根据存储过程的结果,它应该 return 66 条记录。

我对我的 Vb.net 代码有疑问....请提出一些建议..在此先感谢。

    Private Sub GetClients()

      Dim cmd As New OracleCommand("PKG_HOBS.PRC_HOBS_GET_CLIENTID", FPP1_Connection)
    cmd.CommandType = CommandType.StoredProcedure


    Dim p1 As New OracleParameter(":obus_grp_id", OracleDbType.Int32, ParameterDirection.Output)
    p1.CollectionType = OracleCollectionType.PLSQLAssociativeArray
    p1.Size = 100 ' This is the size of items in array in THIS case
    cmd.Parameters.Add(p1)

    Dim p2 As New OracleParameter(":ostat_c", OracleDbType.Int32, ParameterDirection.Output)
    p2.CollectionType = OracleCollectionType.PLSQLAssociativeArray
    p2.Size = 100 ' This is the size of items in array in THIS case
    cmd.Parameters.Add(p2)

    Dim p3 As New OracleParameter(":ostat_msg_x", OracleDbType.Varchar2, ParameterDirection.Output)
    p3.CollectionType = OracleCollectionType.PLSQLAssociativeArray
    p3.Size = 100 ' This is the size of items in array in THIS case
    p3.ArrayBindSize = Enumerable.Repeat(500, 100).ToArray 
    cmd.Parameters.Add(p3)

    cmd.ExecuteNonQuery()

    Dim oraNumbers1() As OracleDecimal = CType(p1.Value, OracleDecimal())
    Dim myobus_grp_idValues(oraNumbers1.Length - 1) As Integer
    For i As Integer = 0 To oraNumbers1.Length - 1
        myobus_grp_idValues(i) = Convert.ToInt32(oraNumbers1(i).Value)
    Next

    Dim oraNumbers2() As OracleDecimal = CType(p2.Value, OracleDecimal())
    Dim myostat_cValues(oraNumbers2.Length - 1) As Integer
    For i As Integer = 0 To oraNumbers2.Length - 1
        myostat_cValues(i) = Convert.ToInt32(oraNumbers2(i).Value)
    Next

    Dim oraStrings() As OracleString = CType(p3.Value, OracleString())
    Dim myostat_msg_xValues(oraStrings.Length - 1) As String
    For i As Integer = 0 To oraStrings.Length - 1
        myostat_msg_xValues(i) = oraStrings(i).Value
    Next

    Try

        MessageBox.Show(myobus_grp_idValues.ToString)

. . . . . 

包定义

 TYPE Tnumber IS TABLE OF NUMBER INDEX BY BINARY_INTEGER; 
 TYPE Tmsg_500 IS TABLE OF VARCHAR2(500) INDEX BY BINARY_INTEGER; 

 PROCEDURE prc_hobs_get_clientid (
     obus_grp_id OUT Tnumber, 
     ostat_c OUT Tnumber, 
     ostat_msg_x OUT Tmsg_500);

首先,不要使用 OleDb,句号。 Microsoft 告诉您使用供应商特定的提供程序。使用 Oracle 的 ODP.NET。

其次,要从 Oracle SP 检索记录集,您需要 return refCursor

编辑:此时我们知道你的参数是table。要处理此问题,您需要将 p.CollectionType = OracleCollectionType.PLSQLAssociativeArray 添加到您的参数

你的代码基本上是这样的:

Declare 
    obus_grp_id PKG_HOBS.Tnumber; -- numeric table value
    ostat_c PKG_HOBS.Tnumber;     -- numeric table value
    ostat_msg_x PKG_HOBS.Tmsg_500; -- string table value
BEGIN  
    PKG_HOBS.PRC_HOBS_GET_CLIENTID(obus_grp_id, ostat_c, ostat_msg_x);
END;

我看到您正在执行匿名块 - 您不需要这样做,因为这会使事情变得复杂。你需要做的是使用 vb.net 直接执行包。

Bottom line: your current ORACLE code does nothing to output results to .NET. Remove anonymous block and you're in business.

这是处理您的程序类型的代码(在评论中阅读)

Dim cmd As New OracleCommand("PKG_HOBS.PRC_HOBS_GET_CLIENTID", conn)
cmd.CommandType = CommandType.StoredProcedure

Dim p1 As New OracleParameter(":p1", OracleDbType.Int64, ParameterDirection.Output)
p1.CollectionType = OracleCollectionType.PLSQLAssociativeArray
p1.Size = 100  ' Declare more than you expect
' This line below is not needed for numeric types (date too???)
' p1.ArrayBindSize = New Integer(99) {} 
cmd.Parameters.Add(p1)

' Add parameter 2 here - same as 1

Dim p3 As New OracleParameter(":p3", OracleDbType.Varchar2, ParameterDirection.Output)
p3.CollectionType = OracleCollectionType.PLSQLAssociativeArray
p3.Size = 100 ' Declare more than you expect
' for string data types you need to allocate space for each element
p3.ArrayBindSize = Enumerable.Repeat(500, 100).ToArray() ' get 100 elements of 500 - size of returning string
' I don't know why you have problems referencing System.Linq but if you do...
'Dim intA() As Integer = New Integer(99) {} 
'For i as integer = 0 to intA.Length -1
'    intA(i) = 500
'Next

cmd.Parameters.Add(p3)
conn.Open()
cmd.ExecuteNonQuery()

' Ora number is not compatible to .net types. for example integer is something 
' between number(9) and (10). So, if number(10) is the type - you get Long in 
' return. Therefore use "Convert" 

' Also, you return arrays, so you need to process them as arrays - NOTE CHANGES


Dim oraNumbers() As OracleDecimal = CType(p1.Value, OracleDecimal())
Dim myP1Values(oraNumbers.Length - 1) As Long
For i as Integer = 0 To oraNumbers.Length - 1
    myP1Values(i) = Convert.ToInt64(oraNumbers(i).Value)
Next

oraNumbers = CType(p2.Value, OracleDecimal())
Dim myP2Values(oraNumbers.Length - 1) As Long
For i as Integer = 0 To oraNumbers.Length - 1
    myP2Values(i) = Convert.ToInt64(oraNumbers(i).Value)
Next    

Dim oraStrings() As OracleString= CType(p3.Value, OracleString())
Dim myP3Values(oraStrings.Length - 1) As String
For i as Integer = 0 To oraStrings.Length - 1
    myP3Values(i) = oraStrings(i).Value
Next

这是最重要的部分

最重要的部分是如何填写声明的类型。让我们

TYPE Tnumber IS TABLE OF NUMBER INDEX BY BINARY_INTEGER;
v_num Tnumber;

v_num(1) := 1234567890;
v_num(2) := 2345678901;
v_num(3) := 3456789012;

这个(以上)会起作用。但这会失败:

v_num(0) := 1234567890;
v_num(1) := 2345678901;
v_num(2) := 3456789012;

最后,这将适用于一个条件

v_num(2) := 1234567890;
v_num(3) := 2345678901;
v_num(4) := 3456789012;

在这里,我们将在 p1.Value 中获得 4 个成员,但在索引 0 下,您将拥有 oracle null。所以,你需要在这里处理(如果你有这种情况)

' instead of this 
myP2Values(i) = Convert.ToInt64(oraNumbers(i).Value)
' you will need first to check 
If oraNumbers(i).IsNull Then 
. . . . 

所以,这里的主要问题是,您的 pl/sql table 的索引是什么?!它需要从大于 0 的东西开始,最好从 1. 开始,如果你有跳过数字的索引,即 2,4,6,8,所有这些空间都将成为一部分returning oracle 数组,其中将有 oracle null

Here is some reference