【问题标题】:How to fix ORA-01422:- Fetch isnt working如何修复 ORA-01422:- Fetch 不起作用
【发布时间】:2020-09-28 02:33:27
【问题描述】:

我不明白为什么会发生此错误。我见过他的例子,但人们不使用 for 或 fetch 循环。据我了解,fetch 会在游标的所有输出中循环,在这种情况下,逐行获取查询并避免此错误。

查看代码:

CREATE OR REPLACE TYPE tab_dias IS TABLE OF INTEGER;

CREATE OR REPLACE FUNCTION  uf_dias_internado_paciente
(v_cod_paciente IN internacao.COD_PACIENTE%TYPE, 
v_dt_inicio IN internacao.DT_HORA_ENTRADA %TYPE, 
v_dt_fim IN internacao.DT_HORA_ALTA %TYPE)
RETURN tab_dias
IS 
    v_dias tab_dias := tab_dias();
    CURSOR c_dias IS
        SELECT EXTRACT(DAY FROM (i.DT_HORA_ALTA - i.DT_HORA_ENTRADA)) AS dias
        FROM INTERNACAO i 
        WHERE i.COD_PACIENTE  = v_cod_paciente
        AND i.DT_HORA_ENTRADA >= v_dt_inicio --13
        AND i.DT_HORA_ALTA <= v_dt_fim;
    linha_dias c_dias%ROWTYPE;
BEGIN 
        OPEN c_dias;
        LOOP
            FETCH c_dias INTO linha_dias;
            EXIT WHEN c_dias%NOTFOUND;
            v_dias(v_dias.last) := linha_dias.dias;
        END LOOP;
        CLOSE c_dias;
        RETURN v_dias;

END;

错误:ORA-01422: exact fetch returns more than requested number of rows

我正在运行的代码:

SELECT uf_dias_internado_paciente (5007, CURRENT_TIMESTAMP - 500000, CURRENT_TIMESTAMP ) FROM DUAL;

想要的输出:

   SELECT (EXTRACT(DAY FROM (i.DT_HORA_ALTA - i.DT_HORA_ENTRADA)))
    FROM INTERNACAO i 
    WHERE i.COD_PACIENTE  = 5007
    AND i.DT_HORA_ENTRADA >= CURRENT_TIMESTAMP - 500000
    AND i.DT_HORA_ALTA <= CURRENT_TIMESTAMP;

(EXTRACT(DAYFROM(I.DT_HORA_ALTA-I.DT_HORA_ENTRADA)))|
----------------------------------------------------|
                                                  11|
                                                   1|
                                                   1|

Oracle 文档: https://docs.oracle.com/cd/B14117_01/appdev.101/b10807/06_ora.htm#i36655 https://docs.oracle.com/cd/B14117_01/appdev.101/b10807/13_elems020.htm

【问题讨论】:

  • 您希望平均返回多少行?是不是很大,超过一百万?

标签: oracle oracle11g database-cursor


【解决方案1】:

代码 - 如你所写 - 将返回

ORA-06502:PL/SQL:数字或值错误:NULL 索引表键值

因为您缺少v_dias.EXTENDORA-01422(即TOO_MANY_ROWS)不会失败;游标不返回它(除非你有一个子查询 - 你没有)。

因此,您发布的代码与您所说的内容有问题。


由于我没有你的表格,这里有一个基于 Scott 的 EMP 表格的示例:

SQL> CREATE OR REPLACE TYPE tab_dias IS TABLE OF INTEGER;
  2  /

Type created.

SQL> CREATE OR REPLACE FUNCTION f_dias (par_deptno IN NUMBER)
  2     RETURN tab_dias
  3  IS
  4     v_dias      tab_dias := tab_dias ();
  5
  6     CURSOR c_dias IS
  7        SELECT empno AS dias
  8          FROM emp
  9         WHERE deptno = par_deptno;
 10
 11     linha_dias  c_dias%ROWTYPE;
 12  BEGIN
 13     OPEN c_dias;
 14
 15     LOOP
 16        FETCH c_dias INTO linha_dias;
 17
 18        EXIT WHEN c_dias%NOTFOUND;
 19        v_dias.EXTEND;                                   --> this
 20        v_dias (v_dias.LAST) := linha_dias.dias;
 21     END LOOP;
 22
 23     CLOSE c_dias;
 24
 25     RETURN v_dias;
 26  END;
 27  /

Function created.

测试:

SQL> SELECT f_dias (10) FROM DUAL;

F_DIAS(10)
--------------------------------------------------------------------------------
TAB_DIAS(7782, 7839, 7934)

或者:

SQL> SELECT * FROM TABLE(f_dias (10));

COLUMN_VALUE
------------
        7782
        7839
        7934

SQL>

也许您应该考虑批量收集,而不是循环;它更简单,更高效:

SQL> CREATE OR REPLACE FUNCTION f_dias (par_deptno IN NUMBER)
  2     RETURN tab_dias
  3  IS
  4     v_dias  tab_dias := tab_dias ();
  5
  6     CURSOR c_dias IS
  7        SELECT empno AS dias
  8          FROM emp
  9         WHERE deptno = par_deptno;
 10  BEGIN
 11     OPEN c_dias;
 12
 13     FETCH c_dias BULK COLLECT INTO v_dias;
 14
 15     CLOSE c_dias;
 16
 17     RETURN v_dias;
 18  END;
 19  /

Function created.

SQL> SELECT * FROM TABLE (f_dias (10));

COLUMN_VALUE
------------
        7782
        7839
        7934

SQL>

所以,基本上,它有效。还有其他东西会产生TOO_MANY_ROWS,而不是您发布的代码。

【讨论】:

  • 这正是我的想法,但我想知道结果集总共有多大,这样你就不能进行批量收集,而是在那里设置一个限制。看起来即使问了 6 个小时,这家伙也不会被打扰。或者可能是他的时区与我的不同。不确定。
猜你喜欢
  • 2023-03-06
  • 1970-01-01
  • 2021-01-18
  • 1970-01-01
  • 2014-04-16
  • 2015-08-17
  • 2020-04-02
  • 2023-03-19
  • 1970-01-01
相关资源
最近更新 更多