If exist then update in oracle forms 11g - oracle

I am trying to write a code block where record insert if record already exist then update
table. i am trying If (sql%rowcount = 0) then but it's not working in cursor and more one records.
What I tried so far as the code block is
declare
remp_id varchar2(60);
remp_name varchar2(100);
rdesig varchar2(100);
rdept_no number;
rdesig_no number;
rdept_name varchar2(60);
cursor alfa is
select emp_code, emp_name, desig, dept_name, dept_no, desig_no
from emp
where emp_code between :first_code and :second_code;
begin
open alfa;
loop
fetch alfa
into remp_id, remp_name, rdesig, rdept_name, rdept_no, rdesig_no;
exit when alfa%notfound;
update att_reg_mo
set emp_code = remp_id,
emp_name = remp_name,
desig = rdesig,
dept_name = rdept_name,
dept_no = rdept_no,
desig_no = rdesig_no,
att_date = :att_date,
emp_att = :emp_att,
att_type = 'MA',
reg_date = :reg_date
where emp_code between :first_code and :second_code
and reg_date = :reg_date
and att_date = :att_date;
commit;
if (sql%rowcount = 0) then
insert into att_reg_mo
(emp_code,
emp_name,
desig,
dept_name,
att_date,
emp_att,
att_type,
reg_date,
dept_no,
desig_no)
values
(remp_id,
remp_name,
rdesig,
rdept_name,
:att_date,
:emp_att,
'MA',
:reg_date,
rdept_no,
rdesig_no);
end if;
commit;
end loop;
close alfa;
end;
when i am fire the trigger then record is insert but where need to update record it's update with null values

Or you could use something like that:
DECLARE
cursor test is
select 1 as v from dual
union
select 2 as v from dual;
n_var NUMBER;
BEGIN
for rec in test loop
BEGIN
select 1 into n_var from dual where rec.v=2;
DBMS_OUTPUT.PUT_LINE('Please Update Any Table');
EXCEPTION
WHEN no_data_found THEN
DBMS_OUTPUT.PUT_LINE('Please Insert Any Table');
END;
end loop;
EXCEPTION
WHEN OTHERS THEN
DBMS_OUTPUT.PUT_LINE ('Unexpected error');
END;

SQL%attribute always refers to the most recently run SELECT or DML statement. It refreshes as to start from zero after any of transaction statement such as COMMIT, ROLLBACK or SAVEPOINT is issued, for a session in which AUTOCOMMIT is presumed to be OFF by default. Therefore, you always get zero from SQL%ROWCOUNT which is just before the INSERT statement, and keeping inserting to the concerned table during every run of code block.
So, remove the f i r s t COMMIT, removing also keeps the atomicity of the whole transaction, from your code block.
Demo

Related

how can i put a query in decode function?

create table ss( no number, filepath varchar2(300) )
I want to have 5 or less duplicate values of 'no' in this table
when select count(no) from ss where no=#{no} <5, insert into ss values({no},{filepath})
so duplicate values of 'no' can't be over 5.
how can i do this?
You could create a similar trigger to implement this logic:
CREATE OR REPLACE TRIGGER set_no_ss_tbl_trg
BEFORE INSERT ON ss_tbl
FOR EACH ROW
BEGIN
DECLARE
l_cnt_no NUMBER;
BEGIN
SELECT COUNT(1)
INTO l_exceeding
FROM g_piece
WHERE refdoss = :new.no;
IF l_cnt_no > 5 THEN
SELECT MIN(no)
INTO :new.no
FROM (SELECT COUNT(1), no
FROM ss_tbl
GROUP BY no
HAVING COUNT(1) + 1 <= 5);
END IF;
END;
END;

Oracle trigger is giving error - active autonomous transaction detected and rolled back

I wrote a trigger which calls a procedure at the end , procedure is having one commit statement .
When i execute trigger then its giving me error "cannot commit in Trigger".
Then i declared PRAGAMA AUTONOMUS_TRANSACTION but that is also giving error "active autonomous transaction detected and rolled back" , "error during execution of trigger"
CREATE OR REPLACE TRIGGER Test_Ord_Update
AFTER
insert or update on test1
for each row
declare
PRAGMA AUTONOMOUS_TRANSACTION;
l_exst number(1);
v_id NUMBER (5);
begin
merge into test2 b
USING dual a
on (:new.id = b.id)
when matched then update set
b.price1 = :new.price1,
b.price2 = :new.price2
when not matched then insert (id, price1, price2)
values (:new.id, :new.price1, :new.price2);
select id into v_id from test2 where price1 = :new.price1;
LOAD_PRICE(v_id);
end;
Whenever we are calling a sub program in a trigger which has commit statement , we must need to write a commit after the line where we called sub program. like below
CREATE OR REPLACE TRIGGER Test_Ord_Update
AFTER
insert or update on test1
for each row
declare
PRAGMA AUTONOMOUS_TRANSACTION;
l_exst number(1);
v_id NUMBER (5);
begin
merge into test2 b
USING dual a
on (:new.id = b.id)
when matched then update set
b.price1 = :new.price1,
b.price2 = :new.price2
when not matched then insert (id, price1, price2)
values (:new.id, :new.price1, :new.price2);
select id into v_id from test2 where price1 = :new.price1;
LOAD_PRICE(v_id);
COMMIT;
end;

Oracle PL/SQL No data found - non consecutive Id values

I have a report with the following structure:
Column 1 ID, Column 2 Approved_Rejected_Status, Column 3 Rep_Id
I'm getting a no data found error while running the following:
DECLARE
V_REP_ID VARCHAR2(100);
V_ROWS_APPROVED_min NUMBER;
V_ROWS_APPROVED_max NUMBER;
V_STAT VARCHAR2(100);
BEGIN
SELECT min(id) INTO V_ROWS_APPROVED_min FROM MY_TABLE;
SELECT max(id) INTO V_ROWS_APPROVED_max FROM MY_TABLE;
FOR i IN V_ROWS_APPROVED_min..V_ROWS_APPROVED_max LOOP
SELECT APPROVED_REJECTED_STATUS INTO V_STAT
FROM MY_TABLE WHERE MY_TABLE.ID =i;
SELECT REP_ID INTO V_REP_ID
FROM MY_TABLE
WHERE MY_TABLE.ID = i;
END LOOP;
END;
I think it has something to do with the ID having non consecutive values perhaps?
(I can't have consecutive values on the report for functionality, neither include an exception cause I need to to perform actions depending on the type_of_change)
Thank you
Edit:
Thank you MT0 for your review/suggestion!
I tried using a cursor for loop and something really weird is happening:
for cur_m in (select id, approved_rejected_status
from bdc_bench_watchlist_t
order by id)
loop
if cur_m.approved_rejected_status = 'Approved' then
--Inserting into a test table:
insert into index_test (ID_COPY, MY_APPROVED_STATUS)
values (cur_m.id, cur_m.approved_rejected_status);
end if;
end loop;
The result brings all the range of IDs (from the min to the max) ok but! the approved_rejected_status column is empty (only the header is showing with null data on the rows). I have no idea why.
If I do a basic select id, approved_rejected_status from the source table it brings everything ok (id and status info ok).
Thank you
Assuming you need to iterate through every number and do something even if there is no row there then just handle the NO_DATA_FOUND exception:
DECLARE
V_REP_ID MY_TABLE.REP_ID%TYPE;
V_ROWS_APPROVED_min MY_TABLE.ID%TYPE;
V_ROWS_APPROVED_max MY_TABLE.ID%TYPE;
V_STAT MY_TABLE.APPROVED_REJECTED_STATUS%TYPE;
BEGIN
SELECT min(id), max(id)
INTO V_ROWS_APPROVED_min, V_ROWS_APPROVED_max
FROM MY_TABLE;
FOR i IN V_ROWS_APPROVED_min..V_ROWS_APPROVED_max LOOP
BEGIN
SELECT APPROVED_REJECTED_STATUS, REP_ID
INTO V_STAT, V_REP_ID
FROM MY_TABLE
WHERE MY_TABLE.ID =i;
EXCEPTION
WHEN NO_DATA_FOUND THEN
V_STAT := NULL; -- Or put default values here.
V_REP_ID := NULL;
END;
-- Do stuff with the stat/rep_id
END LOOP;
END;
If you don't want to iterate through every row and want to skip the missing id values then you could use a cursor and order by id.

Compile error on if else condition in trigger

create or replace
TRIGGER TRG_DEPT_ID BEFORE INSERT ON DEPT FOR EACH ROW
BEGIN
IF NOT EXISTS (SELECT * FROM DEPT cd WHERE cd.st_num = :new.ST_NUMBER AND cd.td_NUMBER = :new.TD_NUMBER)
THEN
SELECT SEQ_DEPT_ID.NEXTVAL INTO :new.ID FROM dual;
ELSE
SELECT ID FROM DEPT INTO :new.ID WHERE cd.st_num = :new.ST_NUMBER AND cd.td_NUMBER = :new.TD_NUMBER;
END IF;
END ;
I am trying to check for duplicate entry. If not exists, then I will create a new Id from sequence. Else I will put the same id.
And the SaveOrUpdate(dept); will do the remaining.
But it gave me compile error.Error(8,9): PL/SQL: SQL Statement ignored.
UPDATE:
When I tried the following query:
CREATE OR REPLACE TRIGGER TRG_DEPT_ID
BEFORE INSERT ON DEPT FOR EACH ROW
BEGIN
BEGIN
SELECT ID
INTO :NEW.ID
FROM DEPT
WHERE cd.st_num = :NEW.ST_NUMBER
AND cd.td_NUMBER = :NEW.TD_NUMBER;
EXCEPTION WHEN no_data_found THEN
SELECT SEQ_DEPT_ID.NEXTVAL INTO :new.ID FROM dual;
END;
END;
Getting the error:
ORA-01422: exact fetch returns more than requested number of rows
How to handle this error?
You can simply code your trigger like this,
CREATE OR REPLACE TRIGGER TRG_DEPT_ID
BEFORE INSERT ON DEPT FOR EACH ROW
BEGIN
BEGIN
SELECT ID
INTO :NEW.ID
FROM DEPT
WHERE cd.st_num = :NEW.ST_NUMBER
AND cd.td_NUMBER = :NEW.TD_NUMBER
AND rownum = 1; --Use rownum = 1 to avoid selecting too many rows.
EXCEPTION WHEN no_data_found THEN
SELECT SEQ_DEPT_ID.NEXTVAL INTO :new.ID FROM dual;
--:NEW.id = seq_dept_id.nextval; -- Or you can use this if you are using 11g or higher versions.
END;
END;
Edited:
You can modify your trigger code as below if duplicate entries are there in your table.
CREATE OR REPLACE TRIGGER TRG_DEPT_ID
BEFORE INSERT ON DEPT FOR EACH ROW
DECLARE
l_id DEPT.id%type;
BEGIN
BEGIN
SELECT ID
INTO l_id
FROM DEPT
WHERE cd.st_num = :NEW.ST_NUMBER
AND cd.td_NUMBER = :NEW.TD_NUMBER
AND ROWNUM = 1; --Use rownum = 1 to avoid selecting too many rows.
IF l_id IS NOT NULL THEN --If same st_number and td_number exists.
raise_application_error( -20001, 'Duplicate entry.');
END IF;
EXCEPTION WHEN no_data_found THEN
SELECT SEQ_DEPT_ID.NEXTVAL INTO :new.ID FROM dual;
--:NEW.id = seq_dept_id.nextval; -- Or you can use this if you are using 11g or higher versions.
END;
END;
try adding rownum in the where section :
CREATE OR REPLACE TRIGGER TRG_DEPT_ID
BEFORE INSERT ON DEPT FOR EACH ROW
BEGIN
BEGIN
SELECT ID
INTO :NEW.ID
FROM DEPT
WHERE cd.st_num = :NEW.ST_NUMBER
AND cd.td_NUMBER = :NEW.TD_NUMBER
AND ROWNUM =1;
EXCEPTION WHEN no_data_found THEN
SELECT SEQ_DEPT_ID.NEXTVAL INTO :new.ID FROM dual;
END;
END;
That will make the query to just return 1 row in case cd.st_num and cd.td_NUMBER are repeated in more than one row.
On the other hand, if you need to detect that there are more than one row for these two columns , you can catch the exception TOO_MANY_ROWS in the exceptions section
EXCEPTION WHEN no_data_found THEN
SELECT SEQ_DEPT_ID.NEXTVAL INTO :new.ID FROM dual;
when TOO_MANY_ROWS then
-- your logic to do when there are too many rows
END;

Can I execute a dynamic sql statement in an after update trigger?

I am using the following statement:
query_str='SELECT :NEW.FIRST_NAME||:NEW.LAST_NAME INTO HostID
FROM INPUT_TABLE WHERE INPUT_ID='
The trigger has the following code:
EXECUTE IMMEDIATE query_str ||:NEW.INPUT_ID;
I'm getting the following error when updating INPUT_TABLE:
ORA-01008: not all variables bound
If I'm updating a record where input_id=111, I would think Oracle would just execute the following statement:
SELECT :NEW.FIRST_NAME||:NEW.LAST_NAME INTO HostID
FROM INPUT_TABLE WHERE INPUT_ID=111
Why is it having binding issues?
I'm using SQLDeveloper.
create or replace
TRIGGER DATA_DETAIL_TRIG
AFTER INSERT OR UPDATE
ON INPUT_TABLE
FOR EACH ROW
DECLARE
DATA_SOURCE_ID_RET NUMBER;
resultcount NUMBER;
query_str VARCHAR2(512);
using_cl VARCHAR2(512);
HostId VARCHAR2(256);
DATA_SOURCE_ID NUMBER;
INPUT_ID NUMBER(38,0);
AUTOGENERATE_IND VARCHAR2(1);
autogen_const varchar(200);
pragma autonomous_transaction;
CURSOR C_DATA_SOURCES IS
SELECT DATA_SOURCE_ID
FROM DATA_SOURCE_DETAIL
WHERE AUTOGENERATE_IND='Y'
AND DATA_SOURCE_REF.ACTIVE_IND='Y';
BEGIN
OPEN C_DATA_SOURCES;
LOOP
FETCH C_DATA_SOURCES INTO DATA_SOURCE_ID_RET;
EXIT WHEN C_DATA_SOURCES%NOTFOUND;
query_str:=getHostQuery( DATA_SOURCE_ID_RET);
--SELECT :FIRST_NAME||:LAST_NAME||to_char(:DOB,'yyyy/mm/dd')
From INPUT_TABLE WHERE INPUT_ID=:INPUT_ID
using_cl:=getHostUsing(DATA_SOURCE_ID_RET);
--:NEW.FIRST_NAME, :NEW.LAST_NAME, :NEW.DOB, :NEW.INPUT_ID
EXECUTE IMMEDIATE query_str INTO HostId USING using_cl;
IF INSERTING THEN
INSERT INTO DETAIL_TABLE
(
DETAIL_ID,
INPUT_ID,
HOST_ID,
DATA_SOURCE_ID,
NOTE,
DATE_MODIFIED
) VALUES
(
DETAIL_SEQ.NEXTVAL,
:NEW.INPUT_ID,
HostId,
DATA_SOURCE_ID_RET,
'Autogenerate Data Source Insert for Insert Input',
SYSDATE
);
ELSIF UPDATING THEN
SELECT COUNT(DATA_SOURCE_ID) INTO resultcount FROM DETAIL_TABLE WHERE
INPUT_ID=:NEW.INPUT_ID AND DATA_SOURCE_ID=DATA_SOURCE_ID_RET;
IF resultcount>0 THEN
UPDATE DETAIL_TABLE
SET
HOST_ID = HostId,
NOTE ='Autogenerate Data Source Update for Update Input',
DATE_MODIFIED =SYSDATE
WHERE INPUT_ID=:NEW.INPUT_ID
AND DATA_SOURCE_ID=DATA_SOURCE_ID_RET;
ELSE
INSERT INTO DETAIL_TABLE
(
DETAIL_ID,
INPUT_ID,
HOST_ID,
DATA_SOURCE_ID,
NOTE,
DATE_MODIFIED
) VALUES
(
DETAIL_SEQ.NEXTVAL,
:NEW.INPUT_ID,
HostId,
DATA_SOURCE_ID_RET,
'Autogenerate Data Source Insert for Update Input ',
SYSDATE
);
END IF;
--end if insert or update inside update
END IF;
--end IF UPDATING
END LOOP;
Close C_DATA_SOURCES;
COMMIT;
END DATA_DETAIL_TRIG;
--end trigger
Once you you placed your :new variables in quotes, Oracle looses their meaning as special trigger variables and interprets them as regular bind variables. You probably need to use USING clause with your dynamic sql. Something like
query_str:='SELECT :FIRST_NAME||:LAST_NAME
FROM INPUT_TABLE WHERE INPUT_ID=:ID';
EXECUTE IMMEDIATE query_str INTO HostID USING
:NEW.FIRST_NAME,:NEW.LAST_NAME,:NEW.INPUT_ID;
Update.
Now as more details emerge, I wonder why do you need to query at all? From what I can see, you just compose HostID from some values in INPUT_TABLE. But since you already have have trigger attached to the same table, you already have all values you need and can simply do
HostID := :NEW.FIRST_NAME||:NEW.LAST_NAME;
Your approach would only make sense if you query different table. In this case, as I mentioned, you can't quote :NEW or :OLD when you place them in USING. You may compose other value from them, though.
#Alex: Below is the trigger.
create or replace
TRIGGER DATA_DETAIL_TRIG
AFTER INSERT OR UPDATE
ON INPUT_TABLE
FOR EACH ROW
DECLARE
DATA_SOURCE_ID_RET NUMBER;
resultcount NUMBER;
query_str VARCHAR2(512);
using_cl VARCHAR2(512);
HostId VARCHAR2(256);
DATA_SOURCE_ID NUMBER;
INPUT_ID NUMBER(38,0);
AUTOGENERATE_IND VARCHAR2(1);
autogen_const varchar(200);
pragma autonomous_transaction;
CURSOR C_DATA_SOURCES IS
SELECT DATA_SOURCE_ID
FROM DATA_SOURCE_DETAIL
WHERE AUTOGENERATE_IND='Y'
AND DATA_SOURCE_REF.ACTIVE_IND='Y';
BEGIN
OPEN C_DATA_SOURCES;
LOOP
FETCH C_DATA_SOURCES INTO DATA_SOURCE_ID_RET;
EXIT WHEN C_DATA_SOURCES%NOTFOUND;
query_str:=getHostQuery( DATA_SOURCE_ID_RET);
--SELECT :FIRST_NAME||:LAST_NAME||to_char(:DOB,'yyyy/mm/dd')
From INPUT_TABLE WHERE INPUT_ID=:INPUT_ID
using_cl:=getHostUsing(DATA_SOURCE_ID_RET);
--:NEW.FIRST_NAME, :NEW.LAST_NAME, :NEW.DOB, :NEW.INPUT_ID
EXECUTE IMMEDIATE query_str INTO HostId USING using_cl;
IF INSERTING THEN
INSERT INTO DETAIL_TABLE
(
DETAIL_ID,
INPUT_ID,
HOST_ID,
DATA_SOURCE_ID,
NOTE,
DATE_MODIFIED
) VALUES
(
DETAIL_SEQ.NEXTVAL,
:NEW.INPUT_ID,
HostId,
DATA_SOURCE_ID_RET,
'Autogenerate Data Source Insert for Insert Input',
SYSDATE
);
ELSIF UPDATING THEN
SELECT COUNT(DATA_SOURCE_ID) INTO resultcount FROM DETAIL_TABLE WHERE
INPUT_ID=:NEW.INPUT_ID AND DATA_SOURCE_ID=DATA_SOURCE_ID_RET;
IF resultcount>0 THEN
UPDATE DETAIL_TABLE
SET
HOST_ID = HostId,
NOTE ='Autogenerate Data Source Update for Update Input',
DATE_MODIFIED =SYSDATE
WHERE INPUT_ID=:NEW.INPUT_ID
AND DATA_SOURCE_ID=DATA_SOURCE_ID_RET;
ELSE
INSERT INTO DETAIL_TABLE
(
DETAIL_ID,
INPUT_ID,
HOST_ID,
DATA_SOURCE_ID,
NOTE,
DATE_MODIFIED
) VALUES
(
DETAIL_SEQ.NEXTVAL,
:NEW.INPUT_ID,
HostId,
DATA_SOURCE_ID_RET,
'Autogenerate Data Source Insert for Update Input ',
SYSDATE
);
END IF;
--end if insert or update inside update
END IF;
--end IF UPDATING
END LOOP;
Close C_DATA_SOURCES;
COMMIT;
END DATA_DETAIL_TRIG;
--end trigger

Resources