需要 ORA-01422 的解决方案:精确提取返回的行数超过请求的行数

Posted

技术标签:

【中文标题】需要 ORA-01422 的解决方案:精确提取返回的行数超过请求的行数【英文标题】:Need solution for ORA-01422: exact fetch returns more than requested number of rows 【发布时间】:2020-03-18 12:16:31 【问题描述】:

我被要求在 Oracle 中为以下查询创建一个存储过程,该过程将在 where 子句中将输入参数作为 @FID 给我结果。

它由 4 列组成,每个不同输入的结果通常是 100+ 行。 初始查询如下-

SELECT 
    TJV.FID, TD.F_CLASS_NAME,  
    CASE 
       WHEN TJV.job_operation_id = 1 THEN 'INSERT' 
       WHEN TJV.JOB_OPERATION_ID = 2 THEN 'UPDATE' 
       WHEN TJV.job_operation_id = 3 THEN 'DELETE' 
    END AS JOB_OPERATION_TYPE, 
    TJV.OPERATION_DATE 
FROM 
    TB_JOB_VERSION TJV, 
    TB_DICTIONARY TD, TB_UFID TU 
WHERE 
    TJV.JOB_ID = @FID 
    AND TU.FID = TJV.FID 
    AND TU.F_CLASS_ID = TD.F_CLASS_ID;

然后我在下面做了一个这样的过程,但它抛出了下面的错误消息 -

ORA-01422:精确提取返回的行数多于请求的行数 ORA-06512:在 TCGM3D.JOB_EXPLORER,第 8 行 ORA-06512:在第 6 行

代码:

CREATE OR REPLACE PROCEDURE job_explorer (
    j_fid IN INT
) AS
    v_fid                  NUMBER;
    v_f_class_name         VARCHAR2(30);
    v_job_operation_type   VARCHAR(100);
    v_operation_date       DATE;
BEGIN
    SELECT
        tjv.fid,
        td.f_class_name,
        CASE
            WHEN tjv.job_operation_id = 1 THEN
                'INSERT'
            WHEN tjv.job_operation_id = 2 THEN
                'UPDATE'
            WHEN tjv.job_operation_id = 3 THEN
                'DELETE'
        END AS job_operation_type,
        tjv.operation_date
    INTO
        v_fid,
        v_f_class_name,
        v_job_operation_type,
        v_operation_date
    FROM
        tcgm3d.tb_job_version   tjv,
        tcgm3d.tb_dictionary    td,
        tcgm3d.tb_ufid          tu
    WHERE
        tjv.job_id = j_fid
        AND tu.fid = tjv.fid
        AND tu.f_class_id = td.f_class_id;

    dbms_output.put_line('FID'
                         || v_fid
                         || 'F_CLASS_NAME'
                         || v_f_class_name
                         || 'JOB_OPERATION_TYPE'
                         || v_job_operation_type
                         || 'OPERATION_DATE'
                         || v_operation_date);

END job_explorer;

我再次尝试使用循环修改查询,但结果不是表格,它只是在查询输出窗口中出现-

"FID85225493
F_CLASS_NAMESCE_EL_TRN_POLE_TBL
JOB_OPERATION_TYPEUPDATE
OPERATION_DATE04-JAN-17
FID251101047
F_CLASS_NAMESCE_EL_SEG_SECTION
JOB_OPERATION_TYPEINSERT
OPERATION_DATE04-JAN-17
FID251101038
F_CLASS_NAMEEL_CONNECTOR
JOB_OPERATION_TYPEINSERT
OPERATION_DATE04-JAN-17
FID251100923
F_CLASS_NAMEEL_PAD
JOB_OPERATION_TYPEINSERT
OPERATION_DATE04-JAN-17"

我对此的最终查询如下-

CREATE OR REPLACE PROCEDURE job_explorer (
    j_fid IN INT
) AS
BEGIN
    FOR rec IN (
        SELECT
            tjv.fid,
            td.f_class_name,
            CASE
                WHEN tjv.job_operation_id = 1 THEN
                    'INSERT'
                WHEN tjv.job_operation_id = 2 THEN
                    'UPDATE'
                WHEN tjv.job_operation_id = 3 THEN
                    'DELETE'
            END AS job_operation_type,
            tjv.operation_date
        FROM
            tcgm3d.tb_job_version   tjv,
            tcgm3d.tb_dictionary    td,
            tcgm3d.tb_ufid          tu
        WHERE
            tjv.job_id = j_fid
            AND tu.fid = tjv.fid
            AND tu.f_class_id = td.f_class_id
    ) LOOP
        dbms_output.put_line('FID' || rec.fid);
        dbms_output.put_line('F_CLASS_NAME' || rec.f_class_name);
        dbms_output.put_line('JOB_OPERATION_TYPE' || rec.job_operation_type);
        dbms_output.put_line('OPERATION_DATE' || rec.operation_date);
    END LOOP;
END job_explorer;

如果有人可以帮助我以表格格式获取每一行的数据,我必须在 ado.net 的数据表中查询这些数据。

【问题讨论】:

只需将 dbms_output.put_line 更改为一次调用并连接所有字段。 另请参阅 Microsoft 文档,了解如何使用 Oracle 引用游标填充数据集。 docs.microsoft.com/en-us/dotnet/framework/data/adonet/… 光标(rec)中的数据是表格的,dbms_output 不是。每次调用 dbms_output.put_line 都会产生 1 行输出。您可以连接每个字段(在字段之间使用合适的分隔符)或将 dbms_output.put_line 更改为 dbms_output.put(然后使用合适的分隔符),然后添加 dbms_output.new_line。 @Belayer -- 我的主要问题是我需要使用这个存储过程来通过 ado dot net dataset/data table 获取数据,我想再次绑定到网格视图但是使用这个数据表只是空 Bad habits to kick : using old-style JOINs - 旧式 逗号分隔的表格列表 样式已替换为 ANSI 中的 proper ANSI JOIN 语法-92 SQL 标准(25 多年前),不鼓励使用它 【参考方案1】:

这样你就可以得到表格形式的答案,用竖线作为分隔符:

CREATE OR REPLACE PROCEDURE job_explorer(j_fid IN INT)
AS
BEGIN
  /* header */
  dbms_output.put_line(       rpad('FID',12)
                       ||'|'||rpad('F_CLASS_NAME',30)
                       ||'|'||rpad('JOB_OPERATION_TYPE',18)
                       ||'|'||rpad('OPERATION_DATE',19)
                       );
  --
  /*data*/
  FOR rec IN (SELECT tjv.fid,
                     td.f_class_name,
                     CASE
                         WHEN tjv.job_operation_id = 1 THEN
                             'INSERT'
                         WHEN tjv.job_operation_id = 2 THEN
                             'UPDATE'
                         WHEN tjv.job_operation_id = 3 THEN
                             'DELETE'
                     END AS job_operation_type,
                     tjv.operation_date
              FROM tcgm3d.tb_job_version   tjv,
                   tcgm3d.tb_dictionary    td,
                   tcgm3d.tb_ufid          tu
              WHERE tjv.job_id = j_fid
               AND tu.fid = tjv.fid
               AND tu.f_class_id = td.f_class_id
              ) LOOP
       --
      dbms_output.put_line(       lpad(rec.fid,12)
                           ||'|'||rpad(rec.f_class_name,30)
                           ||'|'||rpad(rec.job_operation_type,18)
                           ||'|'||to_char(rec.operation_date,'dd-MON-yy')
                          );
  END LOOP;
END job_explorer;

输出将是:

FID      |F_CLASS_NAME                  |JOB_OPERATION_TYPE|OPERATION_DATE
 85225493|SCE_EL_TRN_POLE_TBL           |UPDATE            |04-JAN-17
251101047|SCE_EL_SEG_SECTION            |INSERT            |04-JAN-17
251101038|EL_CONNECTOR                  |INSERT            |04-JAN-17
251100923|EL_PAD                        |INSERT            |04-JAN-17

【讨论】:

我的主要问题是我需要使用这个存储过程来通过 ado dot net dataset/data table 获取数据,我想再次绑定到网格视图,但是数据表只是 null 你可以使用一个输出参数来获取这个输出

以上是关于需要 ORA-01422 的解决方案:精确提取返回的行数超过请求的行数的主要内容,如果未能解决你的问题,请参考以下文章

PL/SQL ORA-01422:精确提取返回的行数超过了请求的行数

获取 ORA-01422 的原因:精确提取返回的行数超过了请求的行数

WHILE循环出错:ORA-01422:精确提取返回的请求行数多于请求的行数

ORA-01422:- ORA-06512:

我在编程中不断遇到此问题

PL/SQL ORA-01422 SELECT INTO 错误,Oracle 匿名块(NOVA 环境)