Updating more than 1 row - Oracle SQL Procedure - oracle

I was wondering if it was possible to update more than 1 row with a procedure, im not sure why this one isnt working. Its working only if theres only 1 row in my table. But if there's more than 1 row i get the usual error message :
ORA-01422: exact fetch returns more than requested number of rows
I'm honestly not sure why this isnt working. Is it possible a procedure cannot update more than 1 row at once ?
create or replace procedure TP3_SP_ARCHIVER_ENCAN
is
V_CURRENT_DATE date;
V_DATE_ENCAN date;
begin
select sysdate, DATE_FIN_ENC into V_CURRENT_DATE, V_DATE_ENCAN
from
TP2_ENCAN;
update TP2_ENCAN
set EST_ARCHIVEE_ENC = 1,
STATUT_ENC = 'Archivé'
where V_CURRENT_DATE - V_DATE_ENCAN > 60;
end TP3_SP_ARCHIVER_ENCAN;
/
I'm excepting to archive every ENCAN that has been closed for a duration of 60+ days. everytime i run this procedure i just want to update those.
Full error message :
Error report -
ORA-01422: exact fetch returns more than requested number of rows
ORA-06512: at "C##JALAC144.TP3_SP_ARCHIVER_ENCAN", line 8
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

This line is your problem:
select sysdate, DATE_FIN_ENC into V_CURRENT_DATE, V_DATE_ENCAN from TP2_ENCAN;
You are selecting DATE_FIN_ENC into a scalar variable that can hold exactly one value. You can select "1" into "x". You can't select "1" and "2" into "x" at the same time. So you get the error you're getting.
If I understand your problem correctly, you probably want this, with no initial select:
update TP2_ENCAN
set EST_ARCHIVEE_ENC = 1,
STATUT_ENC = 'Archivé'
where SYSDATE - DATE_FIN_ENC > 60;

Via your code you just want to update record base on current date. Therefore, you do not need to use parameter. Using the update script is enough.
Create or replace procedure TP3_SP_ARCHIVER_ENCAN is:
begin
update TP2_ENCAN
set EST_ARCHIVEE_ENC = 1,
STATUT_ENC = 'Archivé'
where sysdate - DATE_FIN_ENC > 60;
end
TP3_SP_ARCHIVER_ENCAN;

Related

The number specified in exact fetch is less than the rows returned: is that impossible

I have defined the following procedure in PL/SQL:
CREATE OR REPLACE PROCEDURE deleteFromStudyCase(studycase_id IN NUMBER)
IS
VAL_CARRIER_ID_GLOBAL NUMBER(19,0);
EST_OBJ_ID_GLOBAL NUMBER(19,0);
INVEST_TASK_ID_GLOBAL NUMBER(19,0);
BEGIN
-- Fill the variables
SELECT IT.ID into INVEST_TASK_ID_GLOBAL
FROM T_INVESTIGATIONTASK IT
WHERE IT.STUDYCASE_ID = studycase_id;
SELECT EO.ID into EST_OBJ_ID_GLOBAL
FROM T_ESTIMATIONOBJECT EO
WHERE EO.INVESTIGATIONTASK_ID = INVEST_TASK_ID_GLOBAL;
SELECT VC.ID into VAL_CARRIER_ID_GLOBAL
FROM T_VALIDATIONCARRIER VC
WHERE VC.IA_ESTIMATIONOBJECT_ID = EST_OBJ_ID_GLOBAL;
....many DELETE statements...
END deleteFromStudyCase;
When I try to use it like this:
BEGIN
DELETEFROMSTUDYCASE(30111);
END;
At runtime it fails with this error:
Error report -
ORA-01422: exact fetch returns more than requested number of rows
ORA-06512: at "DELETEFROMSTUDYCASE", line 9
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
Meaning that one of the selects is returning more than just one value as expected. I tried so to run the select statements separately to see which one was the problem but:
SELECT IT.ID
FROM T_INVESTIGATIONTASK IT
WHERE IT.STUDYCASE_ID = 30111;
is returning only 10053.
SELECT EO.ID
FROM T_ESTIMATIONOBJECT EO
WHERE EO.INVESTIGATIONTASK_ID = 10053;
is returning only 933.
SELECT VC.ID
FROM T_VALIDATIONCARRIER VC
WHERE VC.IA_ESTIMATIONOBJECT_ID = 933;
is returning only 12.
Since this part of my database has a tree structure I have also created the following procedure:
CREATE OR REPLACE PROCEDURE deleteFromInvestigationTask(invest_task_id IN NUMBER)
IS
VAL_CARRIER_ID_GLOBAL NUMBER(19,0);
EST_OBJ_ID_GLOBAL NUMBER(19,0);
BEGIN
-- Fill the variables
SELECT EO.ID into EST_OBJ_ID_GLOBAL
FROM T_ESTIMATIONOBJECT EO
WHERE EO.INVESTIGATIONTASK_ID = invest_task_id;
SELECT VC.ID into VAL_CARRIER_ID_GLOBAL
FROM T_VALIDATIONCARRIER VC
WHERE VC.IA_ESTIMATIONOBJECT_ID = EST_OBJ_ID_GLOBAL;
...many DELETE statements...
And this one works correctly.
So the other one should work, why do I continue to get that error? What else could it be?
I found the problem.
In the first procedure, the parameter name is studycase_id which is also the name of a column in the table T_INVESTIGATIONTASK so the WHERE condition IT.STUDYCASE_ID = studycase_id is wrong: that's why the first SELECT is failing. I changed the parameter name in study_case_id and solved my problem.

PLSQL UPDATE OF with Join

I'm trying to create a PLSQL statement that updates the money in the inventory of the characters with the money from all the creatures they've fought
The following is the code I've been trying:
DECLARE
inv_money character.money%TYPE;
CURSOR updmoney IS
SELECT *
FROM character
WHERE id IN (SELECT character_id FROM inst_creature)
FOR UPDATE OF money;
BEGIN
FOR v_character IN updmoney LOOP
SELECT inst_creature.money
INTO inv_money
FROM inst_creature,character
WHERE inst_creature.character_id = character.ID;
UPDATE character
SET money = money+inv_money
WHERE CURRENT OF updmoney;
END LOOP;
COMMIT;
END;
There is a character_id in the inst_creature table which is used to define the character that fought that creature.
I'm getting the error
ORA-01422: exact fetch returns more than requested number of rows.
I've been trying to fix it by using Google to get a solution but nothing has been working so far. Any thoughts?
What happens when a character has killed more than one monster? ORA-01422, that's what. The SELECT ... INTO syntax populates a scalar value, that is one row. When the query returns more than one row PL/SQL hurls ORA-01422.
" Is there any solution to this for it to work?"
The easiest way is to fix the query so it returns one row. As you're just adding money to the character's trove, you can use an aggregate:
SELECT sum(inst_creature.money)
INTO inv_money
FROM inst_creature,character
WHERE inst_creature.character_id = character.ID;
So you get one row per character, and one update per character.

Getting Unknown Command error on IF-THEN-ELSE

I have the following query that I am using in Oracle 11g
IF EXISTS (SELECT * FROM EMPLOYEE_MASTER WHERE EMPID='ABCD32643')
THEN
update EMPLOYEE_MASTER set EMPID='A62352',EMPNAME='JOHN DOE',EMPTYPE='1' where EMPID='ABCD32643' ;
ELSE
insert into EMPLOYEE_MASTER(EMPID,EMPNAME,EMPTYPE) values('A62352','JOHN DOE','1') ;
END IF;
On running the statement I get the following output:
Error starting at line : 4 in command -
ELSE
Error report -
Unknown Command
1 row inserted.
Error starting at line : 6 in command -
END IF
Error report -
Unknown Command
The values get inserted with error when I run it directly. But when I try to execute this query through my application I get an oracle exception because of the error generated :
ORA-00900: invalid SQL statement
And hence the values are not inserted.
I am relatively new to Oracle. Please advise on what's wrong with the above query so that I could run this query error free.
If MERGE doesn't work for you, try the following:
begin
update EMPLOYEE_MASTER set EMPID='A62352',EMPNAME='JOHN DOE',EMPTYPE='1'
where EMPID='ABCD32643' ;
if SQL%ROWCOUNT=0 then
insert into EMPLOYEE_MASTER(EMPID,EMPNAME,EMPTYPE)
values('A62352','JOHN DOE','1') ;
end if;
end;
Here you you the update on spec, then check whether or not you found a matching row, and insert in case you didn't.
"what's wrong with the above query "
What's wrong with the query is that it is not a query (SQL). It should be a program snippet (PL/SQL) but it isn't written as PL/SQL block, framed by BEGIN and END; keywords.
But turning it into an anonymous PL/SQL block won't help. Oracle PL/SQL does not support IF EXISTS (select ... syntax.
Fortunately Oracle SQL does support MERGE statement which does the same thing as your code, with less typing.
merge into EMPLOYEE_MASTER em
using ( select 'A62352' as empid,
'JOHN DOE' as empname,
'1' as emptype
from dual ) q
on (q.empid = em.empid)
when not matched then
insert (EMPID,EMPNAME,EMPTYPE)
values (q.empid, q.empname, q.emptype)
when matched then
update
set em.empname = q.empname, em.emptype = q.emptype
/
Except that you're trying to update empid as well. That's not supported in MERGE. Why would you want to change the primary key?
"Does this query need me to add values to all columns in the table? "
The INSERT can have all the columns in the table. The UPDATE cannot change the columns used in the ON clause (usually the primary key) because that's a limitation of the way MERGE works. I think it's the same key preservation mechanism we see when updating views. Find out more.

Make condition only if "something" - Query Oracle

i'm with a problem in a query.
I have a table called "store" that I need to query.
Select s.store_name
from store s
where s.store = case
when p_store != 0 then
p_store
else
s.store
end;
This should work but as I have "stores" with characters (-) in column and this is defined as number, that query raise an exception: ORA-01722: invalid number.
So I want to do something like this in query:
IF p_store != 0 then
select store_name from store where store = p_store
else
select store_name from store;
Is it possible?
Thanks!
EDIT:
The query that I wrote above was an example of the query I was running.
The exception was raised because another column (too much hours in front of PC :-( ).
This table have a column that's varchar2(15) and I was doing this condition:
(...)AND S.CODE > 4 (...)
The correct condition that I want to do is:
(...)AND LENGTH(S.CODE) > 4
Thank you all!
As far as I understand you have varchar2 s.store which in fact contains numbers so Oracle tries to compare it casting to numbers but at some point it gets - and throws an exception. What you should do is update on table replacing - by null. But if you don't want to do that you can try to make case return varchar2
Select s.store_name
from store s
where s.store = case
when to_char(p_store) != '0' then
to_char(p_store)
else
s.store
end;
I am guessing you are running the query in a plsql block (as cursor?). In that case dynamic sql is the way to go. check out REF CURSOR too (google!).

ORA-01438: value larger than specified precision allowed for this column

Following is my code, I dont understand what I'm doing wrong. Any help will be greatly appreciated
CREATE OR REPLACE
PROCEDURE COMP_LATE_FEE(LATE_APT_FINE IN NUMBER, LATE_GRG_FINE IN NUMBER)
AS
DIFF NUMBER;
TYPE MBCUR IS REF CURSOR RETURN MONTHLY_BILL%ROWTYPE;
MONBILL MBCUR;
MBREC MONTHLY_BILL%ROWTYPE;
BEGIN
--DIFF := FLOOR(SYSDATE - (TRUNC(SYSDATE,'MM')));
--DBMS_OUTPUT.PUT_LINE(DIFF);
OPEN MONBILL FOR
-- checking the status of all last month's bills
SELECT * FROM MONTHLY_BILL
WHERE STATUS = 'PENDING' AND SYSDATE > ED_DT;
FETCH MONBILL INTO MBREC;
-- adding the late fee amount for any bills that are past the due date
-- due date = last day of the month
DIFF := FLOOR(ABS(MBREC.ED_DT - (TRUNC(SYSDATE,'MM'))));
UPDATE MONTHLY_BILL
SET LATE_FEE = DIFF * LATE_APT_FINE
WHERE BILL_NUM = MBREC.BILL_NUM;
-- if a garage is rented by the resident then the respective additional fee is included
IF (MBREC.GARAGE_RENT != 0) THEN
UPDATE MONTHLY_BILL
SET LATE_FEE = LATE_FEE + DIFF * LATE_GRG_FINE
WHERE BILL_NUM = MBREC.BILL_NUM;
END IF;
COMMIT;
CLOSE MONBILL;
END;
/
The procedure compiled without any err. But I get the following err when i call the proc
BEGIN
COMP_LATE_FEE(70,20);
END;
/
Error report:
ORA-01438: value larger than specified precision allowed for this column
ORA-06512: at "LALLURI.COMP_LATE_FEE", line 19
ORA-06512: at line 2
01438. 00000 - "value larger than specified precision allowed for this column"
*Cause: When inserting or updating records, a numeric value was entered
that exceeded the precision defined for the column.
*Action: Enter a value that complies with the numeric column's precision,
or use the MODIFY option with the ALTER TABLE command to expand
the precision.
Assuming that the statement at line 19 is this
UPDATE MONTHLY_BILL
SET LATE_FEE = DIFF * LATE_APT_FINE
WHERE BILL_NUM = MBREC.BILL_NUM;
the problem would appear to be that the result of the computation diff * late_apt_fine is too large for the late_fee column in the monthly_bill table. We know that late_apt_fine is 70 based on the value of the parameter that was passed in. Since we don't know the value of the diff variable when there is an error and we don't know the definition of the late_fee column in monthly_bill, it's hard to know whether the problem is that the definition of late_fee needs to be changed or whether the computed value is larger than you expect and the algorithm needs to be changed.

Resources