PL/SQL Error Return Multiple Rows - oracle

I want to store some results in a temp table after I update a table but it is giving me an error for categories/book types that have multiple entries. Everything works fine when I try to do it with a book type that has one entry. Can someone tell me how I would fix this, I think it's got something to do with not having a filter although I'm not sure how I would do that.
DROP PROCEDURE UpdateAdvance;
CREATE OR REPLACE PROCEDURE UpdateAdvance (
p_BookType titles.category%TYPE,
p_NewAdvance advance_temptable.new_advance%TYPE) AS
CURSOR titles_cur IS
SELECT *
FROM titles
WHERE category=p_BookType
FOR UPDATE OF advance;
titles_rec titles_cur%ROWTYPE;
v_OldAdvance titles.advance%TYPE;
v_TitleID titles.title_id%TYPE;
v_Title titles.title%TYPE;
BEGIN
SELECT advance, title_id, title
INTO v_OldAdvance, v_TitleID, v_Title
FROM titles
WHERE category=p_BookType;
FOR titles_rec in titles_cur LOOP
INSERT INTO advance_temptable VALUES(advance_sequence.nextval, v_TitleID, v_Title, v_OldAdvance, p_NewAdvance);
END LOOP;
COMMIT;
END UpdateAdvance;
When I call it like this
BEGIN
UpdateAdvance('psychology', 100);
END;
I get the error:
Error starting at line : 35 in command -
BEGIN
UpdateAdvance('psychology', 100);
END;
Error report -
ORA-01422: exact fetch returns more than requested number of rows
ORA-06512: at "SYSTEM.UPDATEADVANCE", line 14
ORA-06512: at line 2
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
Applied solution and here is what I now have working.
DROP PROCEDURE UpdateAdvance;
CREATE OR REPLACE PROCEDURE UpdateAdvance (
p_BookType titles.category%TYPE,
p_NewAdvance advance_temptable.new_advance%TYPE) AS
BEGIN
INSERT INTO advance_temptable
select advance_sequence.nextval, title_id, title, advance, p_NewAdvance
FROM titles
WHERE category=p_BookType;
COMMIT;
END UpdateAdvance;
BEGIN
UpdateAdvance('psychology', 100);
END;

Why don't you do:
INSERT INTO advance_temptable
select advance_sequence.nextval, TitleID, Title, Advance, p_NewAdvance
FROM titles
WHERE category = p_BookType;
without cursor?

Related

How could I fix error for Stored Procedure Oracle PL/SQL?

I want to solve this:
Create a stored procedure named insert_num_proc that will insert numbers into the FLOAT_SAMPLE table.
This procedure should have two parameters, one for each of the two columns in this table.
The procedure should check the float_id column to ensure there is no duplicate (as unique values are not enforced in this column). If
there is a duplicate float_id, then the row should not be inserted,
instead printing a message saying “Duplicate value in float_id”.
Below is my query. For the second query, I execute my stored procedure to see if it shows my application error message, and it is not working.
CREATE OR REPLACE PROCEDURE insert_num_proc
(
float_id_param float_sample.float_id%TYPE,
float_value_param float_sample.float_value%TYPE)
AS
float_checker float_sample.float_id%TYPE;
BEGIN
SELECT float_id INTO float_checker FROM float_sample;
INSERT INTO float_sample (float_id, float_value)
VALUES
(float_id_param, float_value_param);
IF float_checker = float_id_param THEN
RAISE_APPLICATION_ERROR(-20001, 'Duplicate value is inserted.');
END IF;
END;
/
EXECUTE insert_num_proc(3,2);
Below is error message I get
Error report - ORA-01422: exact fetch returns more than requested
number of rows ORA-06512: at "DL29232.INSERT_NUM_PROC", line 9
ORA-06512: at line 1
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
You are missing a WHERE clause to check if that id exists, so it returns multiple rows which the single static variable float_checker cannot hold.
Another problem is that if you don't have an entry already in the table, your select statement will fail with no_data_found exception.
So, define your float_checker differently so that it will save the count.
Further, your INSERT should come after the IF condition
CREATE OR REPLACE PROCEDURE insert_num_proc (
float_id_param float_sample.float_id%TYPE,
float_value_param float_sample.float_value%TYPE
) AS
float_checker INTEGER := 0;
BEGIN
SELECT COUNT(*)
INTO float_checker
FROM float_sample WHERE
float_id = float_id_param; --where clause for the passed id.
IF float_checker > 0
THEN
raise_application_error(-20001,'Duplicate value is inserted.');
END IF;
INSERT INTO float_sample (
float_id,
float_value
) VALUES (
float_id_param,
float_value_param
);
END;
/
Since this is an exercise, it's ok to use this code. But, in a real time scenario, the 3rd requirement should be handled by a UNIQUE CONSTRAINT on the table.

ORA-01422: exact fetch returns more than requested number of rows ORA-06512: at "SYSTEM.AA"

I am new to PL/SQL
I was trying to save the deleted record into a temporary table. For that i made a trigger as follows :
create or replace trigger aa
before delete on master_table
declare
v_id number(2);
begin
select id into v_id from master_table;
insert into temp_table values(v_id);
end;
/
But when I try to delete a record from master_table , these exceptions are thrown :
ORA-01422: exact fetch returns more than requested number of rows
ORA-06512: at "SYSTEM.AA", line 4
ORA-04088: error during execution of trigger 'SYSTEM.AA'
Thank you in advance.
You can create the trigger to execute for each row and just use the :old.id to insert value into the temp table.
create or replace trigger aa
before delete on master_table
for each row
begin
insert into temp_table values(:old.id);
end;
/

How to use cursor field in a select query

I am trying to use a cursor here, I would like to know how to i access the cursor field in the select column?
I have an implementation as below,
create or replace TYPE "TABLE_TYPE_SAMPLE" AS OBJECT(
ENTITY_NAME VARCHAR2(100)
);
 
create or replace TYPE "TABLE_SAMPLE" AS TABLE OF TABLE_TYPE_SAMPLE;
 
CREATE OR REPLACE FUNCTION segmentFields(
txnId VARCHAR2)
RETURN TABLE_SAMPLE
IS
attValue VARCHAR2(20);
curStr VARCHAR2(20);
flexTable TABLE_SAMPLE := TABLE_TYPE_SAMPLE();
CURSOR cur_seg
IS
(SELECT colA
FROM table1 -- (table name has column colA)
WHERE id = txnId
);
BEGIN
FOR cur_recd IN cur_seg
LOOP
curStr := cur_recd.colA;
SELECT curStr into attValue FROM PER_PEOPLE_GROUPS;
flexTable.EXTEND;
flexTable(flexTable.count) := (TABLE_TYPE_SAMPLE(attValue)) ;
END LOOP;
RETURN flexTable;
END;
The function complied without errors. but when I try to run below query
select * from table(segmentFields(480));
I get the below error,
ORA-01422: exact fetch returns more than requested number of rows
ORA-06512: at "SEGMENTFIELDS", line 19
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
I want to understand, what is wrong with this implementation.
Thank you.
The problem is with the select into. Not sure why that's there in the first place. The value from your cursor is available in cur_recd.cola and you can use it directly.
create or replace function segmentfields(txnid varchar2) return table_sample is
flextable table_sample := table_type_sample();
cursor cur_seg is(
select cola
from table1 -- (table name has column colA)
where id = txnid);
begin
for cur_recd in cur_seg
loop
flextable.extend;
flextable(flextable.count) := (table_type_sample(cur_recd.cola));
end loop;
return flextable;
end;
This query has no WHERE clause:
SELECT curStr into attValue FROM PER_PEOPLE_GROUPS;
That means it will return hits for all the rows in PER_PEOPLE_GROUPS. The SELECT ... INTO construct populates a single variable and so requires a query which returns exactly one row. The ORA-01422 message indicates that you're not executing an exact fetch, obviously because PER_PEOPLE_GROUPS has more than one row.
Several possible solutions, depending on what you're trying to achieve:
Add a restriction of some kind so that you only return one row from PER_PEOPLE_GROUPS.
Use BULK COLLECT to populate any array instead.
Replace the SELECT with a simple assignment flexTable(flexTable.count) := (TABLE_TYPE_SAMPLE(cur_recd.colA))
On the face of it, discarding the SELECT seems the best option as it doesn't provide you with any information. However, it also seems likely that you are trying to implement some other business logic which isn't expressed in the posted code, so probably you need to make several changes.
error in row:
SELECT curStr into attValue FROM PER_PEOPLE_GROUPS;
that executes the code? how many rows in PER_PEOPLE_GROUPS?
error indicates that more than one. You may need to put a condition in where clause?

PL/SQL: ORA-00932: inconsistent datatypes: expected UDT got NUMBER

I'm executing PL/SQL code to display the Currency Code from the Failed Reservation table. Object type and Nested Table collections are used.
When the PL/SQL code is run, the following error is generated. The corresponding line is highlighted in the PL/SQL code section.
Error report:
ORA-06550: line 27, column 11:
PL/SQL: ORA-00932: inconsistent datatypes: expected UDT got NUMBER
ORA-06550: line 27, column 4:
PL/SQL: SQL Statement ignored
06550. 00000 - "line %s, column %s:\n%s"
*Cause: Usually a PL/SQL compilation error.
*Action:
The code is pasted below:
DDL - Table creation:
CREATE TABLE FAILEDRESERVATION
(
FAILEDRESERVATIONID NUMBER(18,0),
FK_TRANSACTIONID NUMBER(18,0),
DEBITRESERVATIONID NUMBER(18,0),
RESERVATIONTIME DATE,
RESERVATIONAMOUNT NUMBER(18,5),
CURRENCYCODE CHAR(3 BYTE),
AVAILABLEAMOUNT NUMBER(18,5)
);
ALTER TABLE FAILEDRESERVATION
ADD CONSTRAINT "PK_FAILEDRESERVATION" PRIMARY KEY ("FAILEDRESERVATIONID");
Object Type:
CREATE OR REPLACE TYPE TYPE type_failedreservation AS OBJECT
(
FK_TRANSACTIONID NUMBER(18),
DEBITRESERVATIONID NUMBER(18),
RESERVATIONTIME DATE,
RESERVATIONAMOUNT NUMBER(18,5),
CURRENCYCODE CHAR(3),
AVAILABLEAMOUNT NUMBER(18,5)
);
DML:
INSERT INTO FAILEDRESERVATION (FAILEDRESERVATIONID,FK_TRANSACTIONID,DEBITRESERVATIONID,RESERVATIONTIME,RESERVATIONAMOUNT,CURRENCYCODE,AVAILABLEAMOUNT)
VALUES (289,2,1,to_date('07-MAR-16','DD-MON-RR'),20000,'USD',10000);
INSERT INTO FAILEDRESERVATION (FAILEDRESERVATIONID,FK_TRANSACTIONID,DEBITRESERVATIONID,RESERVATIONTIME,RESERVATIONAMOUNT,CURRENCYCODE,AVAILABLEAMOUNT)
VALUES (288,1,1,to_date('01-MAR-16','DD-MON-RR'),10000,'NOK',10000);
Nested Tables:
CREATE OR REPLACE TYPE type_failedreservation_coll as TABLE OF type_failedreservation;
CREATE OR REPLACE TYPE type_dbtrsid_coll AS TABLE OF NUMBER;
PL/SQL Code:
DECLARE
P_FAILEDRESERVATION APPDATA.TYPE_FAILEDRESERVATION_COLL;
vdbtid_coll type_dbtrsid_coll := type_dbtrsid_coll();
BEGIN
SELECT TYPE_FAILEDRESERVATION(fk_transactionid,debitreservationid,reservationtime,reservationamount,currencycode,availableamount)
BULK COLLECT
INTO p_failedreservation
FROM failedreservation;
-- This is line 27
SELECT frs.debitreservationid
INTO vdbtid_coll
FROM TABLE(p_failedreservation) frs;
FOR v_iterate IN vdbtid_coll.FIRST..vdbtid_coll.LAST
LOOP
dbms_output.put_line('The currency code is: '||v_iterate);
END LOOP;
END;
Why is the code generating this error ?
You've declared vdbtid_coll as a collection type, so you need to bulk collect into that too:
SELECT frs.debitreservationid
BULK COLLECT INTO vdbtid_coll
FROM TABLE(p_failedreservation) frs;
With that change:
PL/SQL procedure successfully completed.
The currency code is: 1
The currency code is: 2
That's just giving you the index number in the collection though, so I don't think it's what you really want. You may want:
FOR v_iterate IN vdbtid_coll.FIRST..vdbtid_coll.LAST
LOOP
dbms_output.put_line('The currency code is: '
|| p_failedreservation(v_iterate).currencycode);
END LOOP;
which gets:
PL/SQL procedure successfully completed.
The currency code is: USD
The currency code is: NOK
You don't really need the second select/collection at all though, you can do:
FOR v_iterate IN 1..p_failedreservation.COUNT
LOOP
dbms_output.put_line('The currency code is: '
|| p_failedreservation(v_iterate).currencycode);
END LOOP;
... for the same result. Although I'm not sure what the relevance of the debitreservationid is in that second query, as it is the same value (1) in both rows.
You are trying to select multiple rows into a collection. You need to use BULK COLLECT INTO rather than just INTO.
Change
SELECT frs.debitreservationid
INTO vdbtid_coll
FROM TABLE(p_failedreservation) frs;
To
SELECT frs.debitreservationid
BULK COLLECT INTO vdbtid_coll
FROM TABLE(p_failedreservation) frs;
and you probably want the output to be:
FOR v_iterate IN vdbtid_coll.FIRST..vdbtid_coll.LAST LOOP
dbms_output.put_line('The currency code is: '|| vdbtid_coll(v_iterate) );
END LOOP;
However, you could simplify it all to:
DECLARE
P_FAILEDRESERVATION APPDATA.TYPE_FAILEDRESERVATION_COLL;
BEGIN
SELECT TYPE_FAILEDRESERVATION(
fk_transactionid,
debitreservationid,
reservationtime,
reservationamount,
currencycode,
availableamount
)
BULK COLLECT INTO p_failedreservation
FROM failedreservation;
FOR v_iterate IN p_failedreservation.FIRST .. p_failedreservation.LAST LOOP
dbms_output.put_line(
'The currency code is: '|| p_failedreservation(v_iterate).currencycode
);
END LOOP;
END;
Try casting the type array to its type as follows
SELECT frs.debitreservationid
BULK COLLECT INTO vdbtid_coll
FROM TABLE(CAST(p_failedreservation as APPDATA.TYPE_FAILEDRESERVATION_COLL)) frs;
PL/SQL: ORA-00932: inconsistent datatypes: expected UDT got CHAR
You may get this error in case you write type table in place of type object when
using BULK COLLECT INTO, i faced this error coz i did so.
FOR EXAMPLE:
CREATE OR REPLACE TYPE OBJ_TYPE AS OBJECT (NAME VARCHAR2(20));
/
CREATE OR REPLACE TYPE TBL_TYPE IS TABLE OF OBJ_TYPE;
/
CREATE OR REPLACE FUNCTION FUNC1 RETURN TBL_TYPE AS
TBL_TEXT TBL_TYPE := TBL_TYPE();
BEGIN
SELECT ***OBJ_TYPE*** (NAME) BULK COLLECT INTO ***TBL_TEXT*** FROM <table-name> ;
RETURN ***TBL_TEXT***;
END;
/
Care should be taken when using object type and table type in the function.

Stored Procedure to comapre 2 fields and return mismactch in another table

I am creating stored procedure in Oracle SQL Developer. I am trying to compare two columns form 2 tables and if any table has more records , I need to collect them and store it in ( another table) my stored procedure works fine if I have only one recorded mismatch, anything over one record and it throws
ORA-01422: exact fetch returns more than requested number of rows
ORA-06512: at "TEST_VAL", line 73
ORA-06512: at line 2
here is the query that run just fine if I run it as SQL query
SELECT h.STATEMENTNUMBER, h.STATEMENTTOTAL
FROM statement_header h
MINUS
SELECT j.STATEMENTNUMBER, j.STATEMENTTOTAL
FROM jwf_statement j;
and my stored procedure looks like this
create or replace PROCEDURE TEST_VAL
IS
l_num_recs VARCHAR2 (20);
BEGIN
select STATEMENTNUMBER into l_num_recs
from
(SELECT H.STATEMENTNUMBER, H.STATEMENTTOTAL
FROM statement_header H
MINUS
SELECT J.STATEMENTNUMBER, J.STATEMENTTOTAL
FROM jwf_statement J
);
insert into l_num_recs values(l_num_recs);
Commit;
End;
any help is appriciated
create or replace PROCEDURE TEST_VAL
IS
BEGIN
insert into destinationTableName
select STATEMENTNUMBER
from
(SELECT H.STATEMENTNUMBER, H.STATEMENTTOTAL
FROM erocks.statement_header_staging H
MINUS
SELECT J.STATEMENTNUMBER, J.STATEMENTTOTAL
FROM erocks.ps_jwf_statement_staging J
);
Commit;
End;

Resources