当前位置: 首页 > 面试题库 >

如何在Oracle中获取表作为out参数

司空瑾瑜
2023-03-14
问题内容

我正在尝试将oracle过程调用的out参数强制转换为对象。它不起作用,因为-就我所知-
我需要定义一个映射,告诉该方法如何投射它。如果地图是空的或未正确填充,则默认为STRUCT类型的Objekt-在我的情况下这是错误的。

我建立了一个示例,该示例应说明该问题:

-- Procedure in database
PROCEDURE myprocedure (
inputParam                IN       VARCHAR2 (4),
outputOne                 OUT outputOneSQLType
outputTwo                 OUT outputTwoSQLType);

-- inside of a package
inside a package mypackage

-- first type
create or replace
TYPE outputOneSQLType IS TABLE OF tableOneExample

-- table of type
create or replace
TYPE tableOneExample AS OBJECT (
      somethingOne                 VARCHAR2 (4)
     ,somethingTwo        NUMBER (12)
)

//java from here

import oracle.jdbc.OracleCallableStatement;
import oracle.jdbc.OracleTypes;
import oracle.jdbc.oracore.OracleTypeADT;
import oracle.sql.STRUCT;
...
oracle.jdbc.driver.OracleConnection oracleConn = (oracle.jdbc.driver.OracleConnection) con.getMetaData().getConnection();
final OracleCallableStatement storedProc = (OracleCallableStatement)oracleConn.prepareCall("{call mypackage.myprocedure("+
                ":inputParam, :outputOne, :outputTwo)}");

storedProc.setString("inputParam", "SomeValue");

storedProc.registerOutParameter("outputOne",  OracleTypes.STRUCT, "OUTPUTONESQLTYPE");
storedProc.registerOutParameter("outputTwo",  OracleTypes.STRUCT, "OUTPUTTWOSQLTYPE");

storedProc.execute();

//So far so good

//now I am lost - I need to define the map to get the object? 
//What should be inside the map?
Hashtable newMap = new Hashtable();

newMap.put("outputOneSQLType", ?????.class);

//If the map is empty, it defaults to STRUCT...
final STRUCT myObject =  (STRUCT)storedProc.getObject("somethingOne",newMap);
// myObject.getBytes() gives me an object... but I cannot cast it to anything

由于地图错误,我无法使用以下方式:

final MyClass myObject =  (MyClass)storedProc.getObject("somethingOne",newMap);

我应该如何填写地图?

编辑1

oracle数据库中的条目无法更改。我只被允许使用它们。为此

stmt.registerOutParameter(2, java.sql.Types.ARRAY, "OUTPUTONESQLTYPE");

不起作用。因为一旦不使用“ OracleTypes.STRUCT”,就会引发异常。似乎在outputOneSQLType内部有一个类型为“
OracleTypeCOLLECTION”的对象

当我尝试

 Hashtable newMap = new Hashtable();
newMap.put("outputOneSQLType",OracleTypeCOLLECTION.class);
final OracleTypeCOLLECTION myObject =  (OracleTypeCOLLECTION)storedProc.getObject("somethingOne",newMap);

我有一个例外: InstantiationException: oracle.jdbc.oracore.OracleTypeCOLLECTION

@DazzaL:我将尝试定义一个SQLDATA接口。也许这将是解决方案

解决方案

  1. 准备好的语句应类似于“ begin package.procedure(…); end;”。而 不是 “ {call package.procedure(…)})
  2. 需要一个SQLData接口。

@DazzaL:你统治!谢谢。


问题答案:

您必须定义一个sqldata对象以对此进行映射。

文档:http
:
//docs.oracle.com/cd/E11882_01/java.112/e16548/oraarr.htm#JJDBC28574

例如:

SQL> create or replace TYPE tableOneExample AS OBJECT (
  2        somethingOne                 VARCHAR2 (4)
  3       ,somethingTwo        NUMBER (12)
  4  );
  5  /

Type created.

SQL> create or replace TYPE outputOneSQLType IS TABLE OF tableOneExample;
  2  /

Type created.

SQL>
SQL> create or replace PROCEDURE myprocedure (
  2  inputParam                IN       VARCHAR2,
  3  outputOne                 OUT outputOneSQLType)
  4  as
  5  begin
  6  outputOne  := outputOneSQLType(tableOneExample('a', 1), tableOneExample('b', 2));
  7  end;
  8  /

Procedure created.

现在我们定义SQLDATA接口:

import java.sql.*;

public class TestArr implements SQLData
 {
  private String sql_type;

  public String attrOne;
  public int    attrTwo;

  public TestArr() 
  { 
  }
  public TestArr (String sql_type, String attrOne, int attrTwo)
  {
    this.sql_type = sql_type;
    this.attrOne = attrOne;
    this.attrTwo = attrTwo;
   }

  // define a get method to return the SQL type of the object
  public String getSQLTypeName() throws SQLException
  { 
    return sql_type; 
  }

  // define the required readSQL() method 
  public void readSQL(SQLInput stream, String typeName)
    throws SQLException
  {
    sql_type = typeName;

    attrOne = stream.readString();
    attrTwo = stream.readInt();
  }  
  // define the required writeSQL() method 
  public void writeSQL(SQLOutput stream)
    throws SQLException
  { 
    stream.writeString(attrOne);
    stream.writeInt(attrTwo);
  }
}

确保流写入/读取的输入和顺序与您的oracle类型相同,因为任何不一致都会导致内部表示错误。

然后在主类中,将其映射如下:

CallableStatement stmt = conn.prepareCall("begin myprocedure(?,?); end;");
stmt.setString(1, "foo");
stmt.registerOutParameter(2, java.sql.Types.ARRAY, "OUTPUTONESQLTYPE"); // YOUR ARRAY TYPE (TO MATCH THE API OUTPUT), NOT OBJECT
stmt.execute();
Array arr = stmt.getArray (2);
Map map = conn.getTypeMap();
map.put("TABLEONEEXAMPLE", Class.forName("TestArr")); // YOUR OBJECT TYPE, NOT ARRAY.
Object[] values = (Object[]) arr.getArray();
for (int i=0; i < values.length; i++)
{
  TestArr a = (TestArr)values[i];
  System.out.println("somethingOne: " + a.attrOne);
  System.out.println("somethingTwo: " + a.attrTwo);
}

结果bieng:

M:\Documents\Sample Code\1>javac TestArr.java

M:\Documents\Sample Code\1>javac ArrayTest.java
Note: ArrayTest.java uses unchecked or unsafe operations.
Note: Recompile with -Xlint:unchecked for details.

M:\Documents\Sample Code\SQLComplexArray>java ArrayTest
Opening Oracle connection...done.
somethingOne: a
somethingTwo: 1
somethingOne: b
somethingTwo: 2


 类似资料:
  • 插入查询 查看模型 在我调用上述函数的活动中,我使用了CompositeDisposable。 我实施的方式不对吗?

  • 问题内容: 在PL / SQL(或许多其他语言)中,我可以具有从过程返回的IN OUT或OUT参数。如何在Java中实现类似的目的? 我知道这个窍门: 其中参数表示IN参数,并且参数可以包含返回值。约定是的数组。 有点笨拙。 编辑对答案的反馈 :其他技巧包括: 持有人/包装师类,但我不想介绍任何新类型,回调等。 返回值:我想要一个 通用的 解决方案。即一个涉及多个IN OUT参数。 IN OUT参

  • 我在Oracle数据库中有一个过程,其中有一个数组作为输出参数。在这个过程中,我将所有球队及其得分放入一个数组中。 但是当我尝试用PHP调用这个过程时,我总是会遇到这样的错误: PLS-00306:调用RETRIEVE_RANKING的参数的数量或类型错误 这是我的PHP代码的一部分: 如果我将OUT参数更改为VARCHAR2进行测试,我可以读取结果。但是如果它是一个数组,我就无法使其工作。 所以

  • 问题内容: 我试过了 : 它返回了3列“ TABLE_NAME”,“ TABLE_TYPE”和“ COMMENTS”,但是“ TABLE_NAME”列就像“ encrypted”一样,我需要明确的表名: 我使用TABLE_NAME时未“加密”。 问题答案: 由于10g,Oracle在发出DROP TABLE语句时不会立即删除表。相反,它像这样重命名它们并将它们放入回收站。这使我们能够恢复原本不想删

  • 问题内容: 我的包体内有一个proc: 我在包装规格中公开了这一点。 如何在PL SQL Developer(或类似版本)的新SQL窗口中执行此过程? 问题答案: 您可以相对轻松地执行该过程 当然,这只是将游标返回到调用应用程序。它不执行任何操作来从游标中获取数据,对该数据执行任何操作或关闭游标。假设您的目标是向其中写入一些数据(有时对于原型设计很有用,但生产代码不应该依赖该数据),则可以执行以下