【问题标题】:Cannot perform fetch on a PLSQL statement无法对 PLSQL 语句执行提取
【发布时间】:2021-08-06 10:08:00
【问题描述】:

这是我的桌子

CREATE TABLE accounts (
    accountid        VARCHAR(255),
    name             VARCHAR2(255),
    phone_number     INTEGER,
    email_addresses  VARCHAR2(255),
    account_number   VARCHAR(255),
    password         VARCHAR2(255)
);

现在我创建了一个程序

create or replace PROCEDURE getaccount (
    param1 IN VARCHAR2
) AS
BEGIN
 DBMS_OUTPUT.PUT_LINE('   SELECT
        accountid,
        password
    FROM
        accounts
    WHERE
        account_number = '||param1) ;
END getaccount;

以及我们使用 || 的原因或运算符

第二个我在 SQLDEVELOPER 中运行这段代码 我明白了

call getaccount('123456');

Call completed.

收到此消息

现在我正在连接到 JAVA 这是我的 JAVA 代码

CallableStatement pst = Get.connection().prepareCall("{call getAccount(?)}");
                pst.setString(1, Number);
                ResultSet rs = pst.executeQuery();
                if (rs.next()) {
                    System.out.println(rs.getString(1));    

这里 Get.connection 返回连接。

运行后我得到这个错误

Enter Account Number                       : 123456
java.sql.SQLException: Cannot perform fetch on a PLSQL statement: next
    at ojdbc10/oracle.jdbc.driver.InsensitiveScrollableResultSet.next(InsensitiveScrollableResultSet.java:409)
    at bank.services.SignValidator.getBank(SignValidator.java:20)
    at bank.services.KingobankMain.getBank(KingobankMain.java:49)
    at bank.services.KingobankMain.main(KingobankMain.java:14)

【问题讨论】:

  • 另外,您需要清楚地了解 dbms_output 确实写入屏幕。事实上,PL/SQL 完全在服务器内处理,并且无法访问屏幕。 DBMS_OUTPUT 仅写入缓冲区,然后仅在过程完成时返回给调用者(sqlplus 等)。然后由该调用者处理和显示该缓冲区的内容。一些调用者完全忽略它,其他调用者(如 sqlplus)只有在使用正确的 SET 命令指示这样做时才会处理它。

标签: java oracle ojdbc


【解决方案1】:

我不知道 Java,但是:您编写的过程会导致屏幕上显示输出,但前提是您用来调用该过程的工具支持它 - 例如。 SQL*Plus、SQL Developer、TOAD 等。剩下的,根本就没有结果。

看起来你想跑

select accountid, password from accoutns where account_number = 123456

在 Java 中。然后,您应该使用 函数 而不是过程。它应该返回一个VARCHAR2(即select 语句),然后您将在Java 中执行它。如何?说不出来;正如我所说,我不懂Java。在 Oracle 中,您将使用动态 SQL。

或者,如果它必须是一个过程,那么它应该有一个OUT 参数,以便它将select 语句返回给调用者。但是,调用者必须有“某些东西”(变量?)才能接受该输出。


根据您的要求,带有OUT 参数的过程:

CREATE OR REPLACE PROCEDURE getaccount (param1     IN     VARCHAR2,
                                        par_query     OUT VARCHAR2)
AS
BEGIN
   par_query :=
         'SELECT  accountid,  password  FROM  accounts WHERE '
      || ' account_number = '
      || DBMS_ASSERT.enquote_literal (param1);
END getaccount;

注意dbms_assert,用于防止SQL注入。


为了在 Oracle 中运行它,您必须使用带有变量的 PL/SQL 块,该变量接受该过程返回的结果。

SQL> set serveroutput on
SQL>
SQL> create or replace procedure getaccount (param1     in     varchar2,
  2                                          par_query     out varchar2)
  3  as
  4  begin
  5     par_query :=
  6           'SELECT  accountid,  password  FROM  accounts WHERE '
  7        || ' account_number = '
  8        || dbms_assert.enquote_literal (param1);
  9  end getaccount;
 10  /

Procedure created.

SQL> declare
  2    l_out varchar2(200);
  3  begin
  4    getaccount('12345', l_out);
  5    dbms_output.put_line('Result is: ' || l_out);
  6  end;
  7  /
Result is: SELECT  accountid,  password  FROM  accounts WHERE  account_number = '12345'

PL/SQL procedure successfully completed.

SQL>

显然,您不想返回表示为字符串的命令,而是返回由 select 语句生成的结果。如评论所述,考虑返回一个 refcursor。此外,使用函数而不是过程;它们旨在“返回”一个值。如果它是一个过程,则必须创建 OUT 参数并将其值接受到 something(可能是局部变量)中。

假设这是表格的内容:

SQL> select * From accounts;

 ACCOUNTID PASSWORD   ACCOUNT_NUMBER
---------- ---------- --------------------
         1 my_pwd     12345

SQL>

返回refcursor的函数:

SQL> create or replace function getaccount (param1 in varchar2)
  2    return sys_refcursor
  3  is
  4    l_rc sys_refcursor;
  5  begin
  6    open l_rc for
  7           'SELECT  accountid,  password  FROM  accounts WHERE '
  8        || ' account_number = '
  9        || dbms_assert.enquote_literal (param1);
 10    return l_rc;
 11  end getaccount;
 12  /

Function created.

SQL> select getaccount('12345') from dual;

GETACCOUNT('12345')
--------------------
CURSOR STATEMENT : 1

CURSOR STATEMENT : 1

 ACCOUNTID PASSWO
---------- ------
         1 my_pwd


SQL>

或者,一个带有 2 个 OUT 参数的过程:

SQL> create or replace procedure getaccount
  2    (param1  in  varchar2,
  3     p_accid out varchar2,
  4     p_pwd   out varchar2) is
  5  begin
  6    select accountid,  password
  7      into p_accid, p_pwd
  8    from  accounts
  9    where account_number = param1;
 10  end;
 11  /

Procedure created.

SQL> set serveroutput on
SQL> declare
  2    l_id  varchar2(20);
  3    l_pwd varchar2(20);
  4  begin
  5    getaccount('12345', l_id, l_pwd);
  6    dbms_output.put_line('ID = ' || l_id ||', PWD = ' || l_pwd);
  7  end;
  8  /
ID = 1, PWD = my_pwd

PL/SQL procedure successfully completed.

SQL>

【讨论】:

  • 你能用out参数写吗?我是oracle的新手,在我愉快地使用MySQL之前,但是MYSQL和oracle太不同了
  • 非常感谢您的宝贵重播我非常感谢我认识你们所有人
  • 给你;我添加了一个带有 OUT 参数的过程示例。
  • 我该如何运行这个先生
  • 好的;我编辑了答案并发布了您的要求。看看吧。
【解决方案2】:

您的过程不返回值(输出变量),您正在尝试获取数据。 这会导致错误。

存储过程输出参数

reate or replace procedure getaccount (
    p_account_number  in varchar2,
    p_account_id      out varchar2,
    p_password        out varchar2  
) as
  
begin
     select
        accountid,
        password
     into 
        p_account_id,
        p_password
     from
        accounts
     where
        account_number = p_account_number ; 
end getaccount;
/

CallableStatement pst = Get.connection().prepareCall("{call getAccount(?,?,?)}");
                pst.setString(1, "....");//set account number
                pst.registerOutParameter(2, OracleTypes.VARCHAR);
                pst.registerOutParameter(3, OracleTypes.VARCHAR);               
                pst.execute();
        //read the OUT parameter now
                    
                System.out.println("AccountID="+pst.getString(2)+",password="+pst.getString(3));

..........your  of code....

存储过程 Oracle SYS_REFCURSOR

create or replace procedure getaccount (
    p_account_number in varchar2,
    p_cur            out sys_refcursor
) as
  
begin
 open p_cur for 
 select
        accountid,
        password
    from
        accounts
    where
        account_number = p_account_number ;
end getaccount;
/

CallableStatement pst = Get.connection().prepareCall("{call getAccount(?,?)}");
                pst.setString(1, ".....");// set account number
                pst.registerOutParameter(2, OracleTypes.CURSOR);
                pst.execute();
        //read the OUT parameter now
            rs = (ResultSet) pst.getObject(2);
            
            while(rs.next()){
                System.out.println("AccountID="+rs.getString("accountid")+",password="+rs.getString("password"));
..........your  of code....
}

添加链接:

JDBC Basics

Calling PL/SQL from Java

【讨论】:

  • 在这里我成功运行光标类型,但我想知道如何在 java 中的 sql 中运行它,它正在工作,但我也想在 sqldeveloper 中运行它请
  • 在 java 中我得到了 OUTput 但在 SQLplus 错误中
  • 如何在sqlPlus中运行请帮忙
猜你喜欢
  • 2013-10-26
  • 2015-06-14
  • 2017-08-04
  • 1970-01-01
  • 2012-02-10
  • 2019-11-28
  • 2013-06-28
  • 2016-03-28
  • 2014-01-01
相关资源
最近更新 更多