【问题标题】:Getting ORA-01422: exact fetch returns more than requested number of rows获取 ORA-01422:精确提取返回的行数超过了请求的行数
【发布时间】:2014-04-04 14:18:54
【问题描述】:

我在我的过程中发现“ORA-01422:精确提取返回的行数超过请求的行数”错误,我搜索了它的解决方案并得到一个想法,要解决此类问题,我们必须使用游标或集合在我们的程序中。

我在我的程序中使用光标,逻辑/技术与正常程序有点不同。所以,我很困惑如何更改程序中的逻辑,以便我可以使用集合、记录或批量集合?

谢谢,这是我的程序。

create or replace PROCEDURE DB_TZ_PROC AUTHID CURRENT_USER IS 

V_DBNAME VARCHAR2(20);
V_INSTANCE VARCHAR2(10);
V_TIME VARCHAR2(20);
V_DB_TIME TIMESTAMP(6);
V_SERVER_TZ VARCHAR2(10);
V_RPT_SER_TIME VARCHAR2(50);
V_SERVER_DATE DATE;
V_SESSION_TZ VARCHAR2(30);
V_DBZONE VARCHAR2(10);
V_DATE DATE;
V_ERRORSTRING varchar2(4000);
V_EXEC_STRING VARCHAR2(6000);
TABLE_NAME VARCHAR2(30):='TIMEZONE_DIFF';
INN_EXCEPTION VARCHAR2(30):='INNER_EXCEPTION';
OUT_EXCEPTION VARCHAR2(30):='OUTER_EXCEPTION';


CURSOR DBNAME_CUR IS SELECT DBNAME FROM CRMODDEV.FHM_DB_D WHERE (podname ='xyz');

BEGIN

 OPEN DBNAME_CUR;
LOOP
 FETCH DBNAME_CUR INTO V_DBNAME;
 EXIT WHEN DBNAME_CUR%NOTFOUND;
 DBMS_OUTPUT.PUT_LINE('V_DBNAME1 :'||V_DBNAME);

  BEGIN


 V_EXEC_STRING:='select instance_name,
   startup_time,
   database_default_time,
   server_tz,
   rpt_server_time,
   session_tz, 
   dbtime_zone,
   server_current_date,
   timezone_date
from (select a.inst_id,
    upper(b.instance_name) instance_name,
    to_char(b.startup_time, ''YYYY-MM-DD HH24:MI'') startup_time,
    SYSTIMESTAMP database_default_time,
    substr(to_char(SYSTIMESTAMP), 30) server_tz,
    CURRENT_TIMESTAMP rpt_server_time,
    substr(to_char(CURRENT_TIMESTAMP), 30) session_tz, 
    dbtimezone dbtime_zone,
    to_date(to_char(max(sample_time),''YYYY-MM-DD HH24:MI:SS''),''YYYY-MM-DD HH24:MI:SS'') server_current_date,
    SYSTIMESTAMP AT TIME ZONE ''UTC'' timezone_date 
      from gv$active_session_history@'||V_DBNAME||' a, gv$instance@'||V_DBNAME||' b
    where a.inst_id = b.inst_id
    group by a.inst_id,
    upper(b.instance_name),
    to_char(b.startup_time, ''YYYY-MM-DD HH24:MI''),
    dbtimezone)


    DBMS_OUTPUT.PUT_LINE('V_DBNAME2 :'||V_DBNAME); 

EXECUTE IMMEDIATE  V_EXEC_STRING INTO V_INSTANCE,V_TIME,V_DB_TIME,V_SERVER_TZ,V_RPT_SER_TIME,V_SESSION_TZ,V_DBZONE,V_SERVER_DATE,V_DATE; 


    DBMS_OUTPUT.PUT_LINE('V_INSTANCE:'||V_INSTANCE);
    DBMS_OUTPUT.PUT_LINE('V_SERVER_TZ:'||V_SERVER_TZ);
    DBMS_OUTPUT.PUT_LINE('V_DBZONE:'||V_DBZONE);

  INSERT INTO TIMEZONE_DIFF(DB_INSTANCE,STARTUP_TIME,DATABASE_DEFAULT_TIME,SERVER_TZ,RPT_SERVER_TIME,SESSION_TZ,DBZONE,TIMEZONE_DATE,COLLECTION_DATE) 
VALUES  (V_INSTANCE,V_TIME,V_DB_TIME,V_SERVER_TZ,V_RPT_SER_TIME,V_SESSION_TZ,V_DBZONE,V_DATE,TRUNC(SYSDATE));        

  COMMIT;

  DBMS_OUTPUT.PUT_LINE('V_DBNAME3 :'||V_DBNAME);

  UPDATE TIMEZONE_DIFF SET COLLECTION_DATE=TRUNC(COLLECTION_DATE);               

   COMMIT;

 -- INNER EXCEPTION         
   EXCEPTION

                     WHEN OTHERS THEN                            
       V_ERRORSTRING:= 'INSERT INTO CRMODDEV.TIMEZONE_DIFF_LOG VALUES ('''||V_DBNAME||''','''||TABLE_NAME||''','''||SQLCODE||''','''||SQLERRM||''',SYSDATE,'''||INN_EXCEPTION||''')';
                    EXECUTE IMMEDIATE v_errorstring;
                                          COMMIT;
                   DBMS_OUTPUT.PUT_LINE('DBMS_UTILITY.FORMAT_ERROR_BACKTRACE FOR INNER BLOCK:'||DBMS_UTILITY.FORMAT_ERROR_BACKTRACE);


  END;

 END LOOP;

CLOSE DBNAME_CUR;

 -- OUTER EXCEPTION

 EXCEPTION
           WHEN OTHERS THEN 
V_ERRORSTRING:= 'INSERT INTO CRMODDEV.TIMEZONE_DIFF_LOG VALUES ('''||V_DBNAME||''','''||TABLE_NAME||''','''||SQLCODE||''','''||SQLERRM||''',SYSDATE,'''||OUT_EXCEPTION||''')';
                    EXECUTE IMMEDIATE v_errorstring;
                    COMMIT;
          DBMS_OUTPUT.PUT_LINE('DBMS_UTILITY.FORMAT_ERROR_BACKTRACE FOR OUTER BLOCK:'||DBMS_UTILITY.FORMAT_ERROR_BACKTRACE);


END DB_TZ_PROC;

【问题讨论】:

    标签: oracle stored-procedures


    【解决方案1】:

    当前的问题似乎是您在V_EXEC_STRING 中构建的select 语句返回多行。但是随后您尝试将输出提取到您的EXECUTE IMMEDIATE 中的一组标量变量中。可以将所有变量声明为集合并在这些集合中执行BULK COLLECT。但是由于您所做的只是转身并将结果插入到timezone_diff 表中,因此您确实应该构建一个INSERT ... SELECT 语句,这样您就不必费心将任何数据提取到局部变量中。

     V_EXEC_STRING:='INSERT INTO TIMEZONE_DIFF(DB_INSTANCE,STARTUP_TIME,DATABASE_DEFAULT_TIME,' ||             
                    '                          SERVER_TZ,RPT_SERVER_TIME,SESSION_TZ,DBZONE,' ||
                    '                          TIMEZONE_DATE,COLLECTION_DATE) ' ||
                    ' select instance_name, ' ||
                    ...
    
      EXECUTE IMMEDIATE v_exec_string;
    

    对我来说,您为什么要为插入CRMODDEV.TIMEZONE_DIFF_LOG 而使用动态 SQL 或为什么要在不可重新启动的进程中的循环内提交,这对我来说并不明显。这些事情都不会导致您遇到特定错误,但两者都可能会在某个时候咬您。

    【讨论】:

    • 谢谢@贾斯汀。那么,我必须在这里进行 3 处更改? #1。声明一个集合并将所有变量放入其中。 #2。使用批量收集,我需要将数据推送到集合中的那些变量中。 #3。正如建议的那样,我将使用 Execute immediate v_exec_string; ?
    • @user3181672 - 很可能,您想消除局部变量,只构建我建议的 INSERT ... SELECT 语句。如果您出于某种原因真的想将SELECTINSERT 分开,您可以声明集合并将批量收集到这些集合中。但是,如果您可以在一条 SQL 语句中完成所有操作,那么将数据提取到局部变量中通常是没有意义的。
    • 谢谢@贾斯汀。我想使用嵌套表。所以我创建了类型 - TIMEZONE_DIFF_type 和 TIMEZONE_DIFF_type_details 以及最终将发生插入的表 TIMEZONE_DIFF_1。如何在过程中使用嵌套表将数据插入表中?所有代码都可以在这里找到。 stackoverflow.com/questions/22930684/…
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2013-11-15
    • 1970-01-01
    • 2021-06-14
    • 2015-09-24
    • 1970-01-01
    • 2019-01-27
    相关资源
    最近更新 更多