Ошибка ora 01422 точная выборка возвращает количество строк больше запрошенного

A SELECT INTO statement will throw an error if it returns anything other than 1 row. If it returns 0 rows, you’ll get a no_data_found exception. If it returns more than 1 row, you’ll get a too_many_rows exception. Unless you know that there will always be exactly 1 employee with a salary greater than 3000, you do not want a SELECT INTO statement here.

Most likely, you want to use a cursor to iterate over (potentially) multiple rows of data (I’m also assuming that you intended to do a proper join between the two tables rather than doing a Cartesian product so I’m assuming that there is a departmentID column in both tables)

BEGIN
  FOR rec IN (SELECT EMPLOYEE.EMPID, 
                     EMPLOYEE.ENAME, 
                     EMPLOYEE.DESIGNATION, 
                     EMPLOYEE.SALARY,  
                     DEPARTMENT.DEPT_NAME 
                FROM EMPLOYEE, 
                     DEPARTMENT 
               WHERE employee.departmentID = department.departmentID
                 AND EMPLOYEE.SALARY > 3000)
  LOOP
    DBMS_OUTPUT.PUT_LINE ('Employee Nnumber: ' || rec.EMPID);
    DBMS_OUTPUT.PUT_LINE ('---------------------------------------------------');
    DBMS_OUTPUT.PUT_LINE ('Employee Name: ' || rec.ENAME);
    DBMS_OUTPUT.PUT_LINE ('---------------------------------------------------');
    DBMS_OUTPUT.PUT_LINE ('Employee Designation: ' || rec.DESIGNATION);
    DBMS_OUTPUT.PUT_LINE ('----------------------------------------------------');
    DBMS_OUTPUT.PUT_LINE ('Employee Salary: ' || rec.SALARY);
    DBMS_OUTPUT.PUT_LINE ('----------------------------------------------------');
    DBMS_OUTPUT.PUT_LINE ('Employee Department: ' || rec.DEPT_NAME);
  END LOOP;
END;

I’m assuming that you are just learning PL/SQL as well. In real code, you’d never use dbms_output like this and would not depend on anyone seeing data that you write to the dbms_output buffer.

I’m newbie in plsql.

I’m getting error

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

The problem is that from time to time I need to select from cursor that have duplicate rows
To avoid this situation I tried to add
rownum=1 or rownum<2

But this didn’t solve the issue

select work into my_work  
from INFO 
where person_id = in_person_id
and date= (select max(date) from INFO where (person_id = in_person_id and rownum<2     
));     

P.S. the original bug produce duplicate rows cannot be fixed

asked Dec 20, 2012 at 16:09

Toren's user avatar

Your rownum <2 applied to subquery, not to the main one. It should be

select work into my_work  
from INFO 
where person_id = in_person_id
and date= (select max(date) from INFO where (person_id = in_person_id 
--and rownum<2  
)) 
AND rownum<2  ;     

answered Dec 20, 2012 at 16:13

a1ex07's user avatar

a1ex07a1ex07

36.8k12 gold badges90 silver badges103 bronze badges

1

In my previous articles, I have given the proper idea of different oracle errors, which are frequently come. In this article, I will try to explain another common error, which has been searched on google approximately 10 k times per month. ORA-01422 is another simple error, which is commonly come in database when select into statement when it retrieves more than one row. All oracle errors are categorized in to two types one is network and memory issues and other are syntax errors come due to bad syntax. ORA-01422 is user-initiated mistake resulting from either a typo or a misunderstanding of how Oracle functions may work.

Cause and resolution of this error:

The ORA-01422 error is most common error, which will come because of the multiple reasons .The main reason of this error, is ‘SELECT INTO’ statement. Oracle has one important inbuilt error named ‘TOO_MANY_ROWS’ error.

ORA-01422

1.More than requested rows in “Select into”:

If ‘Select Into’ statement returns more than one rows in variable then this error will come. The error says fetch returns more than requested number of rows means ‘Exact Fetch’ will return ‘More than one row’. The basic problem will come from ‘Select Into’ statement from oracle, which will return more than one rows. The select statement will fetch the record from multiple databases and multiple tables and it will store into variable. The Oracle engine will fetch more than one record for single specified row. The ORA-01422 error will trigger when PLSQL engine returns multiple rows of data. The select into statement has default setting, which is designed to retrieve one row, but when it retrieves more than one rows, the ORA-01422 error will trigger.

Consider following real life example:

If table named ‘test_error’ has more than one records and user tries to fetch all records in to one variable this error will come.

Procedure :

DECLARE

v_test VARCHAR2(30);

BEGIN

SELECT roll_no INTO v_test FROM test_error;    —-Error statement

end;

Output:

Error report:

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

ORA-06512: at line 4

01422. 00000 –  “exact fetch returns more than requested number of rows”

*Cause:    The number specified in exact fetch is less than the rows returned.

*Action:   Rewrite the query or change number of rows requested

Resolution of this error:

Handle the exception:

Just make the small change in the specified code and write the exception block for the same.

Procedure :

DECLARE

V_SRNUM VARCHAR2(20);

DECLARE

v_test VARCHAR2(30);

BEGIN

SELECT roll_no INTO v_test FROM test_error;

exception WHEN too_many_rows THEN

dbms_output.put_line(‘Errors fetching are more than one’);

end;

The above procedure will handle the error and anonyms block will complete successfully.So if this kind of error will occure handle user defined exception named ‘TOO_MANY_ROWS’.

2. Add cursor with loop:

There are many primitive adjustments to resolve this error. The approach needs to be chosen by the user dependent on the database tables and scenarios. The error will occur because of multiple rows are returning so user will change the code by adding the cursor.

Therefore, the above procedure will be:

Declare

v_test VARCHAR2(30);

begin

for c in (SELECT roll_no INTO v_test FROM test_error)

loop

v_test := c.roll_no;

end loop;

end;

3. Recommend to use aggregate function:

This error will come because of multiple rows selection. Therefore, as per requirement if user uses the aggregate function like sum, count then it will fetch only one row.

Therefore, the above procedure will be:

DECLARE

v_test VARCHAR2(30);

BEGIN

SELECT count(roll_no) INTO v_test FROM test_error;    —-Error statement

end;

4. Use of bulk collect:

This will pull more rows and variables but in a concise manner. However, be wary of using BULK COLLECT excessively as it can use a great deal of memory.

So there are different ways to deal with this error, my best recommendation is to use the cursor for fetching more than one rows and processing it.

A SELECT INTO statement will throw an error if it returns anything other than 1 row. If it returns 0 rows, you’ll get a no_data_found exception. If it returns more than 1 row, you’ll get a too_many_rows exception. Unless you know that there will always be exactly 1 employee with a salary greater than 3000, you do not want a SELECT INTO statement here.

Most likely, you want to use a cursor to iterate over (potentially) multiple rows of data (I’m also assuming that you intended to do a proper join between the two tables rather than doing a Cartesian product so I’m assuming that there is a departmentID column in both tables)

BEGIN
  FOR rec IN (SELECT EMPLOYEE.EMPID, 
                     EMPLOYEE.ENAME, 
                     EMPLOYEE.DESIGNATION, 
                     EMPLOYEE.SALARY,  
                     DEPARTMENT.DEPT_NAME 
                FROM EMPLOYEE, 
                     DEPARTMENT 
               WHERE employee.departmentID = department.departmentID
                 AND EMPLOYEE.SALARY > 3000)
  LOOP
    DBMS_OUTPUT.PUT_LINE ('Employee Nnumber: ' || rec.EMPID);
    DBMS_OUTPUT.PUT_LINE ('---------------------------------------------------');
    DBMS_OUTPUT.PUT_LINE ('Employee Name: ' || rec.ENAME);
    DBMS_OUTPUT.PUT_LINE ('---------------------------------------------------');
    DBMS_OUTPUT.PUT_LINE ('Employee Designation: ' || rec.DESIGNATION);
    DBMS_OUTPUT.PUT_LINE ('----------------------------------------------------');
    DBMS_OUTPUT.PUT_LINE ('Employee Salary: ' || rec.SALARY);
    DBMS_OUTPUT.PUT_LINE ('----------------------------------------------------');
    DBMS_OUTPUT.PUT_LINE ('Employee Department: ' || rec.DEPT_NAME);
  END LOOP;
END;

I’m assuming that you are just learning PL/SQL as well. In real code, you’d never use dbms_output like this and would not depend on anyone seeing data that you write to the dbms_output buffer.

In my previous articles, I have given the proper idea of different oracle errors, which are frequently come. In this article, I will try to explain another common error, which has been searched on google approximately 10 k times per month. ORA-01422 is another simple error, which is commonly come in database when select into statement when it retrieves more than one row. All oracle errors are categorized in to two types one is network and memory issues and other are syntax errors come due to bad syntax. ORA-01422 is user-initiated mistake resulting from either a typo or a misunderstanding of how Oracle functions may work.

Cause and resolution of this error:

The ORA-01422 error is most common error, which will come because of the multiple reasons .The main reason of this error, is ‘SELECT INTO’ statement. Oracle has one important inbuilt error named ‘TOO_MANY_ROWS’ error.

ORA-01422

1.More than requested rows in “Select into”:

If ‘Select Into’ statement returns more than one rows in variable then this error will come. The error says fetch returns more than requested number of rows means ‘Exact Fetch’ will return ‘More than one row’. The basic problem will come from ‘Select Into’ statement from oracle, which will return more than one rows. The select statement will fetch the record from multiple databases and multiple tables and it will store into variable. The Oracle engine will fetch more than one record for single specified row. The ORA-01422 error will trigger when PLSQL engine returns multiple rows of data. The select into statement has default setting, which is designed to retrieve one row, but when it retrieves more than one rows, the ORA-01422 error will trigger.

Consider following real life example:

If table named ‘test_error’ has more than one records and user tries to fetch all records in to one variable this error will come.

Procedure :

DECLARE

v_test VARCHAR2(30);

BEGIN

SELECT roll_no INTO v_test FROM test_error;    —-Error statement

end;

Output:

Error report:

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

ORA-06512: at line 4

01422. 00000 –  “exact fetch returns more than requested number of rows”

*Cause:    The number specified in exact fetch is less than the rows returned.

*Action:   Rewrite the query or change number of rows requested

Resolution of this error:

Handle the exception:

Just make the small change in the specified code and write the exception block for the same.

Procedure :

DECLARE

V_SRNUM VARCHAR2(20);

DECLARE

v_test VARCHAR2(30);

BEGIN

SELECT roll_no INTO v_test FROM test_error;

exception WHEN too_many_rows THEN

dbms_output.put_line(‘Errors fetching are more than one’);

end;

The above procedure will handle the error and anonyms block will complete successfully.So if this kind of error will occure handle user defined exception named ‘TOO_MANY_ROWS’.

2. Add cursor with loop:

There are many primitive adjustments to resolve this error. The approach needs to be chosen by the user dependent on the database tables and scenarios. The error will occur because of multiple rows are returning so user will change the code by adding the cursor.

Therefore, the above procedure will be:

Declare

v_test VARCHAR2(30);

begin

for c in (SELECT roll_no INTO v_test FROM test_error)

loop

v_test := c.roll_no;

end loop;

end;

3. Recommend to use aggregate function:

This error will come because of multiple rows selection. Therefore, as per requirement if user uses the aggregate function like sum, count then it will fetch only one row.

Therefore, the above procedure will be:

DECLARE

v_test VARCHAR2(30);

BEGIN

SELECT count(roll_no) INTO v_test FROM test_error;    —-Error statement

end;

4. Use of bulk collect:

This will pull more rows and variables but in a concise manner. However, be wary of using BULK COLLECT excessively as it can use a great deal of memory.

So there are different ways to deal with this error, my best recommendation is to use the cursor for fetching more than one rows and processing it.

A function is meant to return something, while you need to do something, without returning anything, so I would interpret the requirement
as «build a stored procedure».

Now, say you have your procedure, it only has to look for some specific account branch and number, so it would need some input parameters.
Then this procedure should check the (unique?) row in the table to get the status of the account (a select with a WHERE condition based on the values of branch and account number).
Once known the status, the procedure simply has to print a message or do an insert.

With tables like the following

create table ACCOUNT_DATA(account_number, branch, status) as (
    select 1, 'x', 'Active'   from dual union all
    select 2, 'x', 'Inactive' from dual 
)   

create table active_accounts (account_number number, branch varchar2(10))

you could create a procedure like this:

create or replace procedure checkAccount(p_acc_number IN number, p_acc_branch IN varchar2) is
    v_status varchar2(10);
begin
    -- get the status, assuming that the couple (account_number, and branch) is a key for the table 
    select status
    into v_status
    from ACCOUNT_DATA
    where account_number = p_acc_number
      and branch = p_acc_branch;
    -- check the status
    if v_status = 'Active' then
        insert into active_accounts
        values (p_acc_number, p_acc_branch);
    else
       dbms_output.put_line('The account is Inactive.');
    end if;
end;     

Your script could be (test.sql):

SET SERVEROUTPUT ON;
ACCEPT input_accountNumber NUMBER PROMPT 'Enter the account number : '
ACCEPT input_branch CHAR PROMPT 'Enter the branch : '

begin
    checkAccount('&input_accountNumber', '&input_branch');
end;    
/

How it works:

SQL> select * from active_accounts;

no rows selected

SQL> sta d:temptest.sql
Enter the account number : 1
Enter the branch : x

PL/SQL procedure successfully completed.

SQL> sta d:temptest.sql
Enter the account number : 2
Enter the branch : x
The account is Inactive.

PL/SQL procedure successfully completed.

SQL> select * from active_accounts;

ACCOUNT_NUMBER BRANCH
-------------- ----------
             1 x

SQL>

A function is meant to return something, while you need to do something, without returning anything, so I would interpret the requirement
as «build a stored procedure».

Now, say you have your procedure, it only has to look for some specific account branch and number, so it would need some input parameters.
Then this procedure should check the (unique?) row in the table to get the status of the account (a select with a WHERE condition based on the values of branch and account number).
Once known the status, the procedure simply has to print a message or do an insert.

With tables like the following

create table ACCOUNT_DATA(account_number, branch, status) as (
    select 1, 'x', 'Active'   from dual union all
    select 2, 'x', 'Inactive' from dual 
)   

create table active_accounts (account_number number, branch varchar2(10))

you could create a procedure like this:

create or replace procedure checkAccount(p_acc_number IN number, p_acc_branch IN varchar2) is
    v_status varchar2(10);
begin
    -- get the status, assuming that the couple (account_number, and branch) is a key for the table 
    select status
    into v_status
    from ACCOUNT_DATA
    where account_number = p_acc_number
      and branch = p_acc_branch;
    -- check the status
    if v_status = 'Active' then
        insert into active_accounts
        values (p_acc_number, p_acc_branch);
    else
       dbms_output.put_line('The account is Inactive.');
    end if;
end;     

Your script could be (test.sql):

SET SERVEROUTPUT ON;
ACCEPT input_accountNumber NUMBER PROMPT 'Enter the account number : '
ACCEPT input_branch CHAR PROMPT 'Enter the branch : '

begin
    checkAccount('&input_accountNumber', '&input_branch');
end;    
/

How it works:

SQL> select * from active_accounts;

no rows selected

SQL> sta d:temptest.sql
Enter the account number : 1
Enter the branch : x

PL/SQL procedure successfully completed.

SQL> sta d:temptest.sql
Enter the account number : 2
Enter the branch : x
The account is Inactive.

PL/SQL procedure successfully completed.

SQL> select * from active_accounts;

ACCOUNT_NUMBER BRANCH
-------------- ----------
             1 x

SQL>

#sql #oracle #plsql

Вопрос:

Я получаю эту ошибку и не знаю, как ее исправить..

ОБЪЯВИТЬ
*
ОШИБКА в строке 1:
ORA-01422: точная выборка возвращает больше, чем запрошенное количество строк
ORA-06512: в строке 7

Это мой код, который должен подсчитать выходные данные из инструкции SQL и просто напечатать число, но это не сработает

 sqlplus -S "/ as sysdba " <<EOF > /home/oracle/testDaten/Ausgabe.log
set verify off;
set serveroutput on;
set lines 12345 pages 12345;

DECLARE

cnt NUMBER(10);

BEGIN

select count(v.name) into cnt
  from cdb_objects c, v$containers v
 where object_type like '%JAVA%'
   and c.con_id = v.con_id
   and owner not in ('MDSYS', 'OJVMSYS')
   and c.con_id != 1
   group by v.name
    having count(*) > (select count(*) from cdb_objects c2 
                where object_type like '%JAVA%' 
                and c2.con_id = 1 
                and owner not in ('MDSYS', 'OJVMSYS'));
    

    DBMS_Output.put_line(cnt);
 
end;
/
EXIT
EOF
 

Комментарии:

1. Почему у вас есть предложение использовать группу по здесь?

Ответ №1:

В PL/SQL голый ВЫБОР в переменной должен возвращать ровно одну строку. Если он возвращает нулевые строки, вы получите ORA-01403 исключение (данные не найдены), а если он возвращает более одной строки, вы получите ORA-01422 ошибку (точная выборка возвращает больше запрошенного количества строк), которая у вас есть.

Проблема в том, что ваш запрос вернет несколько строк из-за соединения с v$containers .

Решение простое: используйте цикл курсора, чтобы просмотреть отдельные записи и распечатать их одну за другой.

 BEGIN
  for rec in (
    select v.name, count(v.name) cnt
      from cdb_objects c, v$containers v
     where object_type like '%JAVA%'
       and c.con_id = v.con_id
       and owner not in ('MDSYS', 'OJVMSYS')
       and c.con_id != 1
       group by v.name
        having count(*) > (select count(*) from cdb_objects c2 
                    where object_type like '%JAVA%' 
                    and c2.con_id = 1 
                    and owner not in ('MDSYS', 'OJVMSYS'))
  )loop
    dbms_output.put_line(rec.name || ': ' || rec.cnt);
  end loop; 
end;
/
 

Здесь окружите запрос for rec in ( ... ) loop ... end loop;
Запись неявно определена, и вы можете называть ее как угодно (я использовал rec ).

Ссылайтесь на возвращаемые столбцы в цикле так же, как на столбцы таблицы, используя переменную записи.

Несколько приятных побочных эффектов:

  • Вам не нужно объявлять переменную count сейчас, так как она является частью неявной записи.
  • Нет необходимости открывать, извлекать и закрывать курсор, все это делается за вас.
  • Условие «данные не найдены» никогда не возникнет; цикл просто не будет выполняться, если нет совпадающих записей.

Ответ №2:

Ваша ГРУППА ПО пункту является здесь виновником. Просто избавьтесь, и вам хорошо идти —

 DECLARE
cnt NUMBER(10);

BEGIN

     SELECT count(v.name)
       INTO cnt
       FROM cdb_objects c, v$containers v
      WHERE object_type like '%JAVA%'
        AND c.con_id = v.con_id
        AND owner NOT IN ('MDSYS', 'OJVMSYS')
        AND c.con_id != 1
      -- group by v.name
      -- HAVING count(*) > (SELECT count(*)
      --                    FROM cdb_objects c2 
      --                   WHERE object_type LIKE '%JAVA%'
      --                     AND c2.con_id = 1
      --                     AND owner NOT IN ('MDSYS', 'OJVMSYS'));

    DBMS_Output.put_line(cnt);

end;
/
 

Если вы действительно хотите использовать это, пожалуйста, поделитесь своим ожидаемым результатом.

Комментарии:

1. я хочу выбрать все базы данных, в которых больше объектов, чем в других базах данных.. вот так: база данных 1 содержит 10 объектов java, а базы данных 2 и 3 имеют 13 объектов java, поэтому он должен показать мне базы данных 2 и 3, поэтому (количество = 2) вот почему я группирую их с наличием

2. Вам нужен владелец (база данных), у которого максимальное количество объектов отсутствует?

3. нет, я работаю с базой данных с несколькими клиентами, в которой есть более одной базы данных, поэтому я присоединяюсь к контейнерам v$, которые дают мне имена баз данных, Например, есть база данных контейнеров CDB$ROOT

oracle tutorial webinars

ORA-01422

A vast majority of Oracle errors can be broken down into two categories: memory & network problems and issues arising from improper use of syntax & phrasing. Many of the former errors involve interacting with a network administrator to determine where faulty connections and misaligned partitioning of memory are stemming from. The latter, which the ORA-01422 can most aptly identify with, concerns a user-initiated mistake resulting from either a typo or a misunderstanding of how Oracle functions may work.

So what syntax mistakes are causing the ORA-01422 error? Why are they a problem? And most importantly, how can we fix it? Well, let’s start at the beginning and talk briefly about just what exactly an ORA-01422 really is.

The Problem

Oracle describes the ORA-01422 error as the “exact fetch” returning “more than requested number of rows”. The type of vague contextual clue that Oracle attaches to this message concerning the error’s origins can be quite infuriating initially.

The basics of the problem derive from a failed SELECT INTO statement. This statement pulls data from one or more database tables and subsequently assigns the information to specified variables. In its default setting, the SELECT INTO statement will return one or more columns from a single specified row.  This is where the error is being thrown.

When an ORA-01422 is triggered, your SELECT INTO statement is retrieving multiple rows of data or none at all. If it is returning multiple, the predefined exception TOO_MANY_ROWS will be raised, and for no returns the PL/SQL will raise NO_DATA_FOUND. Because the SELECT INTO statement in its default setting is designed to retrieve only one row, the system responds with an error at either one.

The Solution

There are a number of fixes and preemptive adjustments that you can make in order to prevent the issuance of an ORA-01422 error. How you choose to approach it is entirely dependant on your data tables, but we will go over some strategies.

First, to protect against no rows being returned, you can select the result of any type of aggregating function (such as AVG or COUNT). This will be helpful because a function like COUNT will at the least be guaranteed to return some type of value.

Much more common will be an error resulting from multiple rows being returned. An initial step can be to check that the WHERE clause in your statement is exclusive enough to only matchup one row. This will require having knowledge of your rows and how they are similar & different so that you can know how to target results from a particular row.

Another step that you can take to offset multiple row quandaries is to run a BULK COLLECT in a table to pull more variables.  This will pull more rows and variables but in a concise manner. However, be wary of using BULK COLLECT excessively as it can use a great deal of memory.

Finally, a great recommendation would be to replace your SELECT INTO statement with a cursor. A cursor is a tool through which you can give a name to a SELECT statement and change the data within that statement as you please. This will effectively create a loop that will fetch multiple rows without generating the error. Below is an example of what this would look like in action.

Example of ORA-01422 Error

SQL> declare

v_student number;

begin

select student into v_student from michael.std where deptno=12;

end;

/

declare

*

ERROR at line 1:

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

ORA-06512: at line 4

Example of Cursor Solution

SQL>declare

v_student number;

begin

for c in (select student into v_student from Michael.std where deptno=12)

loop

v_student := c.student;

end loop;

end;

/

Looking forward

The ORA-01422 error differs from many in that it could involve a bit of coding on your end to resolve. This is a far cry from the simple Oracle errors that simply require changing the punctuation of a statement quickly and moving on. With that said, the tools above should be plenty to get started and work to develop a solution. In the event that you find yourself completely lost, it can never hurt to contact a licensed Oracle consultant for more information.

Вопрос:

Итак, я работаю над установщиком, где установщик подключается к базе данных и создает таблицы и заполняет их.
Каждый аспект этого работает правильно, за исключением случаев, когда я пытаюсь добавить строки в таблицу certian.

declare
retVal INTEGER;
rptID INTEGER;
catID INTEGER;
wsID INTEGER;
paramID INTEGER;
dtID INTEGER;
begin

select PK into catID from RPT_CATEGORY where KEYVALUE = 'ProductivityReportsCategory';
select PK into rptID from RPT_REPORT where KEYVALUE = 'ProductivitySummaryReport2';
select PK into wsID from RPT_WEBSVC where KEYVALUE = 'NotApplicable' and category_fk = catID;

Операторы select, которые заполняют базу данных, выглядят следующим образом:

  select PK into wsID from RPT_WEBSVC where KEYVALUE = 'GetMachineNameList' and category_fk = catID;
paramID := RPT_CONFIGURATION.ADD_PARAMETER( rptID, wsID, dtID, 'Machine', 'parameters.GetProductivityDataSet3.inserterid', 4, NULL, NULL, NULL, 0, 0, 0, 'Y', 'Y', 'N', 'N', 'Y' );

Есть еще 13 операторов выражений, структурированных таким образом (я не буду добавлять их, поскольку они все одинаковы, и единственное различие – это сохраненные значения, которые будут входить в таблицу.)

Моя проблема в том, что когда я запускаю установщик, я получаю эту ошибку в журналах после завершения:

ORA-01422: exact fetch returns more than requested number of rows
ORA-06512: at line 30

Что я хотел бы знать, в чем именно причина этой ошибки, и каковы были бы способы исправить эту ошибку?

Я провел некоторое исследование по этой теме и нашел, что это общая тема моего поиска:

1. В коде есть ошибка, и разработчик не понял, что вы можете получить более одной строки;

2. Данные были взломаны, а не используются API, так что проверка была нарушена;

3. Программное обеспечение в порядке, то, что сделал пользователь, было ОК, но одновременно выполнялось два параллельных обновления, и ни одно из них не могло видеть незафиксированное изменение, которое было сделано другим, поэтому оно не было правильно проверено.

Я уверен, что это не # 2, но я не совсем понимаю, что именно означают другие 2 причины или как их исправить.

Любая помощь или предложения приветствуются.

Спасибо

Лучший ответ:

ORA-01422: точная выборка возвращает больше запрошенного количества строк

Это исключение возникает всякий раз, когда выполняется инструкция SELECT INTO и находит более одной строки. Оператор SELECT INTO ожидает найти ровно одну строку, не более или менее – в противном случае возникает исключение.

В вашем примере:

select PK into wsID from RPT_WEBSVC
where KEYVALUE = 'GetMachineNameList'
and category_fk = catID;

Кажется, что должна быть только одна строка за (KEYVALUE, CATEGORY_FK) комбинация, но на самом деле это не так. Если должно быть только одно, то таблица должна иметь уникальное ограничение для этих столбцов:

alter table RPT_WEBSVC add constraint RPT_WEBSVC_UK
    unique (KEYVALUE, CATEGORY_FK);

Это помешает кому-то (или некоторому процессу) снова добавить ту же строку. Конечно, вам нужно будет удалить дубликаты таблицы, прежде чем вы сможете добавить это ограничение.

Ответ №1

Это означает, что оператор “SELECT INTO” возвращает более одной строки. Это утверждение требует, чтобы запрос возвращал только одну строку. В противном случае вы должны использовать цикл курсора для обработки строк.

Проверьте свои операторы select в SQL * Plus, чтобы узнать, какой из них является нарушающим запрос.

Ответ №2

Я бы рассмотрел номер 1 как причину проблемы здесь. Не видя всех утверждений, трудно сказать, какой из этих запросов может возвращать несколько строк, но это хорошее место для запуска, поскольку база данных схемы могут меняться…

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

Cause:

The number specified in exact fetch is less than the rows returned.

Solution:

Rewrite the query or change number of rows requested.

Example:

declare
    v_name varchar2(255);  
begin
    select name 
    into v_name 
    from books 
    where id=2;
    dbms_output.put_line('The name is: '||v_name);
end;

Output:

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

Correct

declare
    v_name varchar2(255);
    v_rows number;
begin
    select name 
    into v_name 
    from books 
    where id=2;
    dbms_output.put_line('The name is: '||v_name);
exception 
when too_many_rows then
	select count(*) into v_rows 
	from books where id=2;
	dbms_output.put_line('Error, rows = '||v_rows);
end;

Output:

Error, rows = 2

  • Ошибка ora 01008 not all variables bound
  • Ошибка ora 01002 fetch out of sequence
  • Ошибка ora 00972 identifier is too long
  • Ошибка ora 00936 отсутствует выражение
  • Ошибка ora 00920 invalid relational operator