pls 00905 object is invalid - oracle

create or replace procedure p_update_project_status(v_project_id in number(10)) is
declare
v_bid_file_status number(2);
v_bid_form_status number(2);
v_supplier_status number(2);
begin
select status into v_bid_file_status from PROJECT_FILE where type = 0 and associated_project_id = v_project_id;
select status into v_bid_form_status from PROJECT_FILE where type = 1 and associated_project_id = v_project_id;
select status into v_supplier_status from SUPPLIER_INFO where associated_project_id = v_project_id;
if( (v_bid_file_status = 3) and (v_bid_form_status = 3) and (v_supplier_status = 3) ) then
update PROJECT_INFO set status = 3 where id = v_project_id;
else
update PROJECT_INFO set status = 0 where id = v_project_id;
end if;
end;
I execute the procedure,but it's invalid, I have tried my best to correct it, but still invalid.I don't know where is going wrong.Please help me

DECLARE keyword is not necessary here. You need it only if youre running an anonymous block. Remove that and it should compile.

Related

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

I am asked to make a stored procedure in Oracle for the below query which would take input parameter as #FID in there where clause to give me the result.
It consists of 4 columns and the result normally is 100+rows for each of the different inputs.
The initial query is below-
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;
I have then made a procedure like this below but it has thrown the below error message -
ORA-01422: exact fetch returns more than requested number of rows
ORA-06512: at TCGM3D.JOB_EXPLORER, line 8 ORA-06512: at line 6
Code:
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;
I have again tried modifying the query using a loop but the results are not tabular and it just comes out like this in the query output window-
"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"
My final query for this is below-
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;
It would help if anyone could help me out in getting the data in tabular format for each row which i then has to query in a datatable in ado.net.
With this you get answers in tabular form with pipes as delimiter:
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;
And output will be:
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

Check ID Exist and delete record in PL SQL

What I have to do is, whenever a STORE_CODE is entered it will check in the db and delete the store code. SO for that, I have written a procedure which is as below
PROCEDURE DELETE_STORE_INFO
(
P_STORE_CODE IN NVARCHAR2
)
AS
BEGIN
UPDATE TBL_RRSOC_STORE_INFO set ISACTIVE = 'N' where STORE_CODE = P_STORE_CODE;
END DELETE_STORE_INFO;
But here what missing is
what if the user enter the wrong store_code and does the operation so what it will do. how to check with that part ?
I guess something for COUNT wont work at this stage. Kindly suggest
You want to use SQL%ROWCOUNT to find out how many rows were affected by the previous SQL statement:
PROCEDURE DELETE_STORE_INFO
(
P_STORE_CODE IN NVARCHAR2
)
AS
BEGIN
UPDATE TBL_RRSOC_STORE_INFO
SET ISACTIVE = 'N'
WHERE STORE_CODE = P_STORE_CODE;
IF SQL%ROWCOUNT = 0 THEN
-- DBMS_OUTPUT.PUT_LINE( 'Store code does not exist.' );
RAISE_APPLICATION_ERROR( -20000, 'Store code does not exist.' );
END IF;
END DELETE_STORE_INFO;
/
You can use DBMS_OUTPUT.PUT_LINE( string ) to output to the SQL console (if you are calling this from an external language like PHP or Java then you will not see the output and you may not see it in the console if you have SET SERVEROUTPUT OFF).
You could also use RAISE_APPLICATION_ERROR( error_code, error_message ) to raise an exception if something invalid happens.
Alternatively you could return a status in an OUT parameter:
PROCEDURE DELETE_STORE_INFO
(
P_STORE_CODE IN NVARCHAR2,
O_STATUS OUT NUMBER
)
AS
BEGIN
UPDATE TBL_RRSOC_STORE_INFO
SET ISACTIVE = 'N'
WHERE STORE_CODE = P_STORE_CODE;
IF SQL%ROWCOUNT = 0 THEN
o_status := 0;
ELSE
o_status := 1;
END IF;
END DELETE_STORE_INFO;
/
Generally contract for your procedure is: caller gives some store_code and procedure guarantee that there is no active store with such code. What if caller gives the wrong store_code? It means there is no such store, so contract is accomplished. You should do nothing, no more :)
But if you wish to check whether update found the record or not, you can add something like
if sql%notfound then
dbms_output.put_line('There is no such store!');
end if;
immediately after update statement.
Especially for MT: just check simple script
create table t$(id integer);
insert into t$ values(1);
set serveroutput on
begin
update t$ set id = 2 where id = 1;
if sql%notfound
then dbms_output.put_line('#1: not found');
else dbms_output.put_line('#1: found');
end if;
update t$ set id = 4 where id = 3;
if sql%found then
dbms_output.put_line('#2: found');
else dbms_output.put_line('#2: not found');
end if;
end;
/
drop table t$;
My results are
Connected to Oracle Database 12c Enterprise Edition Release 12.1.0.2.0
#1: found
#2: not found
PL/SQL procedure successfully completed
There are something missunderstand in your request: you said you want to delete it but in the code, you just updated the store as incative.
Here is the proceure with both situation. You choose the right one:
CREATE OR REPLACE PROCEDURE DELETE_STORE_INFO (P_STORE_CODE IN NVARCHAR2) AS
n_count number;
BEGIN
select count(1) INTO n_count from TBL_RRSOC_STORE_INFO where STORE_CODE = p_store_code;
if n_count > 0 then
UPDATE TBL_RRSOC_STORE_INFO set ISACTIVE = 'N' where STORE_CODE = P_STORE_CODE;
-- or for deletion
-- DELETE TBL_RRSOC_STORE_INFO set ISACTIVE = 'N' where STORE_CODE = P_STORE_CODE;
else
DBMS_OUTPUT.PUT_LINE('the required store was not found');
end if;
END DELETE_STORE_INFO;

New/Old variable in SQL update statement

How can i update the old row value. I have used the :old variable but it does not work for me. Herein my code, if PID already exists in project table i.e. (varProjectExists = 1) then i update the payment term. Now, if payment term is null , i want to update with previous paymnent term value else new payment term that is flown
CREATE OR REPLACE TRIGGER TRIG_PROJECT_INSERT AFTER
INSERT ON TEST_SYN_EAI_PROJECT_IN FOR EACH row DECLARE varError_Msg NVARCHAR2(100);
varSucceeded NVARCHAR2(1);
varActive_YN NVARCHAR2(50);
varProject_Id INT;
varPid INT ;
varPay_Term VARCHAR2(200);
varPay_Term1 VARCHAR2(200);
varError_id INT;
varCurr_activeyn INT;
varProjectExists NUMBER;
BEGIN
varError_Msg := 'No error';
varSucceeded := 'Y';
varError_id := 0;
varProjectExists := 0;
varPID := :new.pid;
varPay_Term := :new.ATTRIBUTE1;
varPay_Term1 := :old.ATTRIBUTE1;
varActive_YN := :new.active_yn;
varProject_ID := :new.project_id;
IF (NVL(varProject_Id,0) = 0 ) THEN
varError_Msg := 'project ID can not be null';
varSucceeded := 'N';
varError_id := 1;
END IF;
SELECT
CASE
WHEN (UPPER(varActive_YN) = 'ACTIVE'
OR UPPER(varActive_YN) = 'Y')
THEN 1
WHEN (UPPER(varActive_YN) = 'INACTIVE'
OR UPPER(varActive_YN) = 'N')
THEN 0
ELSE varcurr_activeyn
END
INTO varActive_YN
FROM Dual;
SELECT COUNT(1)
INTO varProjectExists
FROM project
WHERE ProjectUniversalID = varProject_ID;
IF (varProjectExists = 1) THEN
UPDATE project
SET PID = varPID,
PAYMENTTERM =
CASE
WHEN varPay_Term = 'NULL'
THEN varPay_Term1
WHEN varPay_Term IS NULL
THEN varPay_Term1
ELSE varPay_Term
END
ELSE .....
The OLD pseudo-record refers to the pre-update state of the current row, and so is only meaningful during an update or delete operation. If you're inserting a new record there is no 'old' state to refer to.
From your comment you want to use the previous payment term value that already exists in the PROJECT table. That would't be available in OLD anyway as it isn't the table the trigger is against. If that is the case then you need to retrieve it at the same time you check that it exists. Something like:
CREATE OR REPLACE TRIGGER TRIG_PROJECT_INSERT
AFTER INSERT ON TEST_SYN_EAI_PROJECT_IN
FOR EACH ROW
DECLARE
...
BEGIN
...
varPay_Term := :new.ATTRIBUTE1;
-- varPay_Term1 := :old.ATTRIBUTE1; -- not valid
varActive_YN := :new.active_yn;
...
-- this doesn't need to select from dual, you can assign directly
varCurr_activeyn := CASE
WHEN (UPPER(varActive_YN) = 'ACTIVE'
OR UPPER(varActive_YN) = 'Y')
THEN 1
WHEN (UPPER(varActive_YN) = 'INACTIVE'
OR UPPER(varActive_YN) = 'N')
THEN 0
ELSE varCurr_activeyn
END CASE;
-- get the current term as you check if a record exists
SELECT COUNT(1), MAX(PAYMENTTERM)
INTO varProjectExists, varPay_Term1
FROM project
WHERE ProjectUniversalID = varProject_ID;
IF (varProjectExists = 1) THEN
UPDATE project
SET PID = varPID,
PAYMENTTERM =
CASE
WHEN varPay_Term = 'NULL'
THEN varPay_Term1
WHEN varPay_Term IS NULL
THEN varPay_Term1
ELSE varPay_Term
END
...
The MAX() is needed because you're already using an aggregate COUNT(), to avoid a no-data-found error if the ID doesn't exist. Assuming that ID is unique, it doesn't matter if you use MAX or MIN, the result is the same. (If it isn't unique then you'd have to decide which term value to use, so it's probably a safe assumption).

PL/SQL how to check if exists and return error code

Disregard if using MERGE INTO is better in this case or not. I just wonder if I can check if the row exists or not. If not, then set the return code to 1 and return immediately. If yes, then continue to execute the rest of code and set return code to 0 in the end. Below code is not working as it always executes to the end. How should I fix it?
BEGIN
-- check
SELECT CASE
WHEN NOT EXISTS (SELECT 1 FROM s WHERE s.col1 = 1 AND s.col2 = 2)
THEN 1
END
INTO ret FROM dual;
-- update
UPDATE s
SET s.col3 = 3
WHERE s.col1 = 1 AND s.col2 = 2;
COMMIT;
SELECT 0 INTO ret FROM dual;
RETURN ret;
END foo;
What if I want be able to distinguish if it's s.col1 = 1 not exist or s.col2 = 2 not exist. And have 2 different return codes for them. How should I do in this case?
I'm wondering if thre is any point checking if the row exists in the first place and why you just don't issue the UPDATE straightaway?
Could you not do something like this?
BEGIN
-- update
UPDATE s
SET s.col3 = 3
WHERE s.col1 = 1 AND s.col2 = 2;
COMMIT;
IF SQL%ROWCOUNT = 0 THEN
RETURN 0;
ELSE
RETURN 1;
END IF;
END foo;
You are not doing anything with the value stored ret.
There is no IF around the UPDATE statement that checks if ret is 1 or null (the other alternative). And because there is no IF the rest of the procedure is always executed.
Something like this is needed:
SELECT sum(case when col1 = 1 then 1 else 0 end) as col1_count,
sum(case when col2 = 2 then 1 else 0 end) as col2_count
into ret1, ret2
FROM s
WHERE s.col1 = 1
or s.col2 = 2;
if ret1 > 0 and ret2 > 0 then
update ...;
commit;
ret := 0;
elsif (ret1 > 0 and ret2 = 0) then
ret := 1;
elsif (ret1 = 0 and ret2 > 0) then
ret := 2;
end if;
return ret;
A much more efficient approach is to simply do the update and check if any rows where modified. Running the select before doing the update simply doubles the work if the row exists. Running only the update when the row does not exist is the same work as doing the select.
What if I want be able to distinguish if it's s.col1 = 1 not exist or
s.col2 = 2 not exist. And have 2 different return codes for them. How
should I do in this case?
I've probably over-complicated it with a BULK COLLECT - especially if the update is for only one row at any one time - but you can of course modify the code accordingly - the principle remains the same.
The code aims to return 1,2 or 3 depending on which UPDATE condition is met regarding col1 and col2.
DECLARE
TYPE test_rec is record ( .... );
TYPE result_tab IS TABLE OF test_rt%ROWTYPE;
lt_results result_tab;
lv_ret NUMBER(1) := 0;
BEGIN
SELECT x.* FROM (
SELECT s.*, 1 as ret
FROM s
WHERE s.col1 = 1 and s.col2 != 2
UNION ALL
(SELECT s.*, 2
FROM s
WHERE s.col1 =! 1 and s.col2 = 2)
UNION ALL
(SELECT s.*, 3
FROM s
WHERE s.col1 = 1 and s.col2 = 2))
BULK COLLECT INTO lt_results;
FOR i in lt_results.first .. lt_results.last LOOP
<<DO YOUR UPDATE>>
lv_ret := lt_results(i).ret;
END LOOP;
COMMIT;
RETURN lv_ret;
END;

PL/SQL Statement ignored error occurs

in bellow code PL/SQL Statement ignored error occurs error accurs line is in bold and italic fonts
create or replace
TRIGGER TRGBILLINGADDRESS
AFTER UPDATE ON TBLMACCOUNTADDRESS
FOR EACH ROW
DECLARE
add1 VARCHAR2(100);
add2 VARCHAR2(100);
cityid VARCHAR2(75);
stateid VARCHAR2(75);
pincd VARCHAR2(10);
BEGIN
SELECT address1,address2,city_id,state_id,pincode
INTO add1,add2,cityid,stateid,pincd FROM wom.tbltaddress ta WHERE ta.ID IN (
SELECT vbac.billing_address_id
FROM wom.vw_billaddresschange vbac, wom.tbltaddress ita
WHERE vbac.billing_address_id = ita.ID
AND vbac.lcid = parlcid);
***IF add1 = :NEW.address1 AND add2 = :NEW.address2 AND cityid = :NEW.cityid AND stateid = :NEW.stateid AND pincode = :NEW.zip THEN***
dbms_output.put_line('Address Already Exist in tbltaddress table');
ELSE
UPDATE wom.tbltaddress ta
SET ta.address1 = :NEW.address1,
ta.address2 = :NEW.address2,
***ta.city_id = :NEW.cityid*,**
ta.country_id = 'CTR0001',
ta.state_id = :NEW.stateid,
ta.pincode = :NEW.zip
WHERE ta.ID IN (
SELECT vbac.billing_address_id
FROM wom.vw_billaddresschange vbac, wom.tbltaddress ita
WHERE vbac.billing_address_id = ita.ID
AND vbac.lcid = parlcid);
END IF;
END;
Your variable is declared as pincd, not pincode. pincode is the field in the table.

Resources