使用游标并使用Java/JDBC在Oracle PL/SQL中获取结果

我有一个像这样构造的PL / SQL查询:

DECLARE
a NUMBER;
B NUMBER;
CURSOR cursor
IS
 ( SOME SELECT QUERY);
BEGIN
  OPEN cursor;
    LOOP
    SOME STUFF;
    END LOOP;
  CLOSE cursor;
END

如何使用jdbc从java代码运行此查询并获取结果集?我已经尝试运行查询而不使用游标,并且它正确运行.我无法想出在java代码中执行此操作的方法.如果我直接在oracle客户端上运行查询,它可以正常工作.所以查询没有问题.

附:我不希望将代码存储为存储过程并由于某些约束而调用它.

最佳答案
这是不可能的.您无法从匿名PL / SQL块返回结果集(因此无法从JDBC获取它).

您需要直接从JDBC运行select.

唯一的,非常丑陋的解决方法是使用dbms_output.put_line()和之后的读取.但这是一个非常丑陋的黑客,直接在JDBC中处理SELECT查询的结果要好得多.

编辑1

这是使用dbms_output的一个小例子:

Connection con = ....;

// turn on support for dbms_output
CallableStatement cstmt = con.prepareCall("{call dbms_output.enable(32000) }");
cstmt.execute();

// run your PL/SQL block
Statement stmt = con.createStatement();
String sql =
    "declare  \n" +
    " a number;  \n" +
    " cursor c1 is select id from foo;  \n" +
    "begin  \n" +
    "  open c1; \n" +
    "  loop \n" +
    "    fetch c1 into a;  \n" +
    "    exit when c1%notfound;  \n" +
    "    dbms_output.put_line('ID: '||to_char(a)); \n" +
    "  end loop; \n" +
    "end;";
stmt.execute(sql);

// retrieve the messages written with dbms_output
cstmt = con.prepareCall("{call dbms_output.get_line(?,?)}");
cstmt.registerOutParameter(1,java.sql.Types.VARCHAR);
cstmt.registerOutParameter(2,java.sql.Types.NUMERIC);

int status = 0;
while (status == 0)
{
    cstmt.execute();
    String line = cstmt.getString(1);
    status = cstmt.getInt(2);
    if (line != null && status == 0)
    {
        System.out.println(line);
    }
}

编辑2(评论太长了)

嵌套循环来检索数据几乎总是一个坏主意.如果你发现自己做了这样的事情:

begin
  for data_1 in (select id from foo_1) loop
    dbms_output.put_line(to_char(data_1.id));

    for data_2 in (select f2.col1, f2.col2 from foo_2 f2 where f2.id = data_1.id) loop
        ... do something else
    end loop;

  end loop;
end;
/

这样做效率会高得多:

begin
  for data_1 in (select f2.col1, f2.col2 from foo_2 f2
                 where f2.id in (select f1.id from foo_1 f1)) loop

     ... do something

  end loop;
end;
/

这可以在没有过多内存的情况下使用以下内容处理:

String sql = "select f2.col1, f2.col2 from foo_2 f2 where f2.id in (select f1.id from foo_1 f1)";
Statement stmt = connection.createStatement();
ResultSet rs = stmt.executeQuery(sql);
while (rs.next())
{
   String col1_value = rs.getString(1);
   int    col2_value = rs.getInt(2);
   ... do something
}

即使您处理了数十亿行,上面的代码也只会在内存中保留一行.确切地说:JDBC驱动程序实际上会预取多行.默认值为10,可以更改.但即使这样,你也没有过多的内存使用量.

转载注明原文:使用游标并使用Java/JDBC在Oracle PL/SQL中获取结果 - 代码日志