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.
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.
Вопрос:
Итак, я работаю над установщиком, где установщик подключается к базе данных и создает таблицы и заполняет их.
Каждый аспект этого работает правильно, за исключением случаев, когда я пытаюсь добавить строки в таблицу 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 как причину проблемы здесь. Не видя всех утверждений, трудно сказать, какой из этих запросов может возвращать несколько строк, но это хорошее место для запуска, поскольку база данных схемы могут меняться…
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.
Are you saying that you get an «ORA-01422: exact fetch returns more than requested number of rows» when you run both of those queries? That seems highly unlikely since you’re including the predicate rownum <= 1
. Can you cut and paste from a SQL*Plus session that runs just this query in a PL/SQL block and generates the error?
If you are not complaining about the error you mention in the title, and the problem is just that you’re not getting the data you expect, the likely problem is that you apparently have a bookDate
parameter that has the same name as a column in your table. That is not going to work. When you say
(to_char(booking.bookdate,'dd-mon-yy'))=(to_char(bookDate,'dd-mon-yy'))
you presumably mean to compare the bookDate
column in the booking
table against the bookDate
parameter. But since column names have precedence over local variables, the left-hand side of your expression is also looking at the bookDate
column in the booking
table. So you’re comparing a column to itself. It would make much more sense to change the name of the parameter (to, say, p_bookDate
) and then write
booking.bookDate = p_bookDate
or, if you want to do the comparison ignoring the time component of the dates
trunc( booking.bookDate ) = trunc( p_bookDate )
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