PLSQL 过程中的查询必须返回 1 行,但返回更多行

Posted

技术标签:

【中文标题】PLSQL 过程中的查询必须返回 1 行,但返回更多行【英文标题】:Query in Procedure PLSQL must return 1 row, but return more rows 【发布时间】:2011-01-13 09:37:55 【问题描述】:

我在实现 pl/sql 过程时遇到了一个奇怪的问题。 我的程序有四个 varchar 输入参数,并从表中提取一个 id 值,查询如下:

SELECT ID INTO idvar FROM TABLE T WHERE T.NAME = pn AND T.SUR = ln;

在此表中,name 和 sur 是唯一键。所以对于几个输入参数(pn,ln),我希望只获得一行,但事实并非如此。 确实,似乎只处理了第一个条件,而第二个没有。

在我的表中,这个测试行:

ID | NAME | SUR
1  | JO   | SOME THING
2  | JO   | OTHER ONE
3  | BO   | SOME THING

如果在我的程序中我通过了

('JO', 'SOME THING')

我获得 ID:1 和 2。 但是如果我传递值

('BO', 'SOME THING')

我只获得 ID 3。

显然,在之前的查询中我得到了错误 ORA-01422,所以我先用游标定义替换它,然后用“for row in (query)”替换它:

CURSOR C IS
SELECT ID FROM TABLE T WHERE T.NAME = pn AND T.SUR = ln;

这种行为对我来说很奇怪,实际上如果我只执行来自 sqlplus 或 toad 的查询,我会得到正确的结果。

Oracle 版本是 8.1。

提前致谢

#

这是我的程序(我希望你没有发现不匹配,因为我更改了对象的名称):

CREATE OR REPLACE PROCEDURE myproc (
pn in VARCHAR2,
ln in VARCHAR2,
other in VARCHAR2,
datarif in VARCHAR2
) 
AS
  idT    NUMBER;
  idST NUMBER;
  idSE    NUMBER;

  CURSOR C IS 
    SELECT ID
    FROM TABLE T
    WHERE 
    T.NAME = pn AND T.SUR = ln;

BEGIN

     for x in ( SELECT ID
         FROM TABLE T
        WHERE 
        T.NAME = pn AND T.SUR = ln )
     loop 
       DBMS_OUTPUT.put_line('INFOR:' || x.ID);
     end loop;


     open C;
     loop
       fetch C into idT;
        exit when C%NOTFOUND;
        DBMS_OUTPUT.put_line('INLOOP:ID='||idT);
 end loop;
 close C;

 DBMS_OUTPUT.put_line ( 'OUTLOOP: ID='||idT );


  EXCEPTION
    WHEN NO_DATA_FOUND THEN
     NULL;
    WHEN TOO_MANY_ROWS THEN 
      RAISE_APPLICATION_ERROR(-20001, 'Exact Fetch Returned many Rows');  
    WHEN OTHERS THEN
     DBMS_OUTPUT.put_line('ERROR');
     ROLLBACK;
 RAISE;

END myproc;
/

谢谢

【问题讨论】:

你能贴出完整的过程和过程的调用(带上下文)吗? 我在原帖上写程序。 【参考方案1】:

也许你的参数和表格的字段有冲突?

通过添加过程名称作为参数范围来更改它:

 T.NAME = myproc.pn AND T.SUR = myproc.ln

【讨论】:

添加范围似乎是解决方案。非常感谢。【参考方案2】:

“...因为我更改了对象的名称”

也许您的某些参数与某些列具有相同的名称。

例如,如果您的程序如下所示:

CREATE OR REPLACE PROCEDURE myproc (
pn in VARCHAR2,
sur in VARCHAR2,
other in VARCHAR2,
datarif in VARCHAR2
)
...
SELECT ID INTO idvar FROM TABLE T WHERE T.NAME = pn AND T.SUR = sur;
...

您会收到 TOO_MANY_ROWS 错误,因为条件“T.SUR = sur”与“T.SUR = T.SUR”的效果相同。

【讨论】:

【参考方案3】:

我用您的示例表测试了您的第一条语句!在我的机器上它可以工作。但那是一个 Oracle 10g 数据库。

编辑: 我重新编写了您的程序,并且在我的机器上该版本运行良好!

create or replace
PROCEDURE myproc (
  pn in VARCHAR2,
  ln in VARCHAR2,
  other in VARCHAR2,
  datarif in VARCHAR2
) 
AS
  idvar    NUMBER;
BEGIN
  SELECT ID INTO idvar FROM TEST T WHERE T.NAME = pn AND T.SUR = ln;
  DBMS_OUTPUT.put_line ( 'OUTLOOP: ID='||idvar );
END myproc;

【讨论】:

添加 ROWNUM=1 不是很好的建议。如果查询在不应该返回多行时,它可能表示编码错误(这似乎是每个接受的答案的情况)。因此,简单地通过“随机”选择其中一行来解决它并不是一个好的解决方案。 @Dave Costa:你是对的!我删除了肮脏的解决方案。但有时为了测试我会再次使用它......;)

以上是关于PLSQL 过程中的查询必须返回 1 行,但返回更多行的主要内容,如果未能解决你的问题,请参考以下文章

PLSQL使用游标或函数查询重复数据

IBM ACE - 调用 Oracle 过程返回一个行类型(通过 ESQL 计算节点)

PLSQL--游标

PostgreSQL存储过程-基于SQL的存储过程

PostgreSQL存储过程-基于SQL的存储过程

SQL如何显示查询结果的前100条?