Count is not working in trigger using condition - oracle

Hi could you please suggest I am trying to check if count =2
When Condition meet (DA.matr_ID = '478') or (DA.matr_ID = '40') then
insert into table, but in any condition like (DA.matr_ID = '479') it insert the data which is wrong
CREATE OR REPLACE TRIGGER DEVICE_TMP_TR
AFTER INSERT OR UPDATE ON DEVICE_ATTRIBUTES_TMP
REFERENCING OLD AS old NEW AS new
FOR EACH ROW
DECLARE
pragma autonomous_transaction;
V_COUNT NUMBER;
BEGIN
SELECT COUNT(*)
INTO V_COUNT
FROM DEVICE_ATTRIBUTES_TMP DA
WHERE DA.DVS_ID = :new.DVS_ID
AND (DA.matr_ID = '40' or DA.matr_ID = '478');
IF V_COUNT = 2 THEN
INSERT Into APP_DELETED_TMP
(sdmid,appid,devis,des_nr,creation_date,creation_user,ant_id)
VALUES
('121213', '23', '45','63',SYSDATE,'hhdhSH',21);
COMMIT;
ELSE
RETURN;
END IF;
END;

Related

I'm facing error in trigger(Encountered the symbol "IF" when expecting one of the following: ; <an identifier> <a double-quoted delimited-identifier>)

--I am a beginner in oracle and facing an error while executing a trigger and need your help
CREATE OR REPLACE TRIGGER hamza
AFTER INSERT OR UPDATE ON RAW_MATERAIL
FOR EACH ROW
DECLARE
VAR number;
BEGIN
SELECT COUNT(*) into VAR FROM ROW_STOCK WHERE MATERIAL_ID = :NEW.MATERIAL_ID ;
IF nvl(VAR,0) = 0 THEN
begin
INSERT INTO RAW_STOCK
(MATERIAL_ID, WEIGHT_OF_MATERIAL) values
(:new.MATERIAL_ID, :new.WEIGHT);
exception
when dup_val_on_index then
null;
end if;
ELSE VAR > 0 THEN
begin
UPDATE RAW_STOCK
SET WEIGHT_OF_MATERIAL= nvl(WEIGHT_OF_MATERIAL,0) + nvl(:NEW.WEIGHT,0)
WHERE MATERIAL_ID = :NEW.MATERIAL_ID ;
end if;
END;
Every IF has to have its END IF; the same goes for BEGIN, which has to have its END.
CREATE OR REPLACE TRIGGER hamza
AFTER INSERT OR UPDATE
ON RAW_MATERAIL
FOR EACH ROW
DECLARE
VAR NUMBER;
BEGIN
SELECT COUNT (*)
INTO VAR
FROM ROW_STOCK
WHERE MATERIAL_ID = :NEW.MATERIAL_ID;
IF VAR = 0
THEN
BEGIN
INSERT INTO RAW_STOCK (MATERIAL_ID, WEIGHT_OF_MATERIAL)
VALUES (:new.MATERIAL_ID, :new.WEIGHT);
EXCEPTION
WHEN DUP_VAL_ON_INDEX
THEN
NULL;
END;
ELSIF VAR > 0
THEN
UPDATE RAW_STOCK
SET WEIGHT_OF_MATERIAL =
NVL (WEIGHT_OF_MATERIAL, 0) + NVL (:NEW.WEIGHT, 0)
WHERE MATERIAL_ID = :NEW.MATERIAL_ID;
END IF;
END;

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;

If exist then update in oracle forms 11g

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

How Can I code a "IF UPDATING" trigger in Oracle Database 10g?

I'm coding a Trigger to ensure only one type of money can be set as official. My intention is code a "BEFORE INSERT OR UPDATE" trigger. The INSERT section works fine but the problem is coding the UPDATING section because when I try to update the table I recieve ORA-04091 "mutanting table". Do you have any idea?
Table (Only one record can be set as 'Y'):
mon_id mon_description mon_official
----------------------------------------------
E EUR N
D DOL N
P PES Y
Trigger:
CREATE OR REPLACE TRIGGER mon_oficial_ins_trg
BEFORE
INSERT OR UPDATE
ON monedas
FOR EACH ROW
DECLARE
v_count NUMBER(8);
BEGIN
IF INSERTING THEN
SELECT COUNT(mon_oficial)
INTO v_count
FROM monedas
WHERE mon_oficial = 'Y';
IF v_count = 1 THEN
RAISE_APPLICATION_ERROR(
-20010, 'Only one record can be set as 'Y'');
END IF;
END IF;
IF UPDATING THEN
SELECT COUNT(:OLD.mon_oficial)
INTO v_count
FROM monedas
WHERE :OLD.mon_oficial = 'Y';
IF v_count = 1 AND :NEW.mon_oficial = 'Y' THEN
RAISE_APPLICATION_ERROR(
-20010, 'Only one record can be set as 'Y'');
END IF;
END IF;
END mon_oficial_ins_trg;
/
SHOW ERRORS;
In your code there are 2 mistake
first
SELECT COUNT(:OLD.mon_oficial)
INTO v_count
FROM monedas
WHERE :OLD.mon_oficial = 'Y';
part, for more information about mutanting error you can read this article
enter link description here
and second mistake, you have a incorrect logic in
IF v_count = 1 AND :NEW.mon_oficial = 'Y' THEN part because it can be our current row
try it
CREATE OR REPLACE TRIGGER mon_oficial_ins_trg
BEFORE
INSERT OR UPDATE
ON monedas
FOR EACH ROW
DECLARE
v_count NUMBER(8);
BEGIN
IF INSERTING THEN
SELECT COUNT(mon_oficial)
INTO v_count
FROM monedas
WHERE mon_oficial = 'Y';
IF v_count = 1 THEN
RAISE_APPLICATION_ERROR(
-20010, 'Only one record can be set as 'Y'');
END IF;
END IF;
IF UPDATING THEN
IF :NEW.mon_oficial = 'Y' then
for m in (SELECT *
FROM monedas
WHERE mon_oficial = 'Y'
and rownum=1) loop
IF :NEW.mon_id <> m.mon_id THEN
RAISE_APPLICATION_ERROR(
-20010, 'Only one record can be set as 'Y'');
END IF;
END IF;
end loop;
END IF;
END mon_oficial_ins_trg;
/
SHOW ERRORS;
This can be done quite simply with an AFTER INSERT OR UPDATE statement trigger. The same logic is applicable to both operations.
SELECT COUNT(*) INTO v_count FROM MONEDAS
WHERE MON_OFICIAL = 'Y';
IF v_count > 1 THEN
RAISE_APPLICATION_ERROR...
Another advantage of this approach: it allows the statement
UPDATE MONEDAS SET MON_OFICIAL = CASE MON_ID WHEN 'A' THEN 'Y' ELSE 'N' END;
to work without a problem when the row-level trigger might raise an error if the row with MON_ID = 'A' is updated to Y before the previous official currency is updated to N.
I think this problem would better be solved with a constraint, instead of a trigger. I am not the author of this answer, but I think it's relevant here. In the rest of the answers there was a link to a blog post that recommends avoiding triggers, but that link doesn't seem to work.
The answer is found here:
https://stackoverflow.com/a/182427
Here's the example provided in that answer by #tony-andrews:
create unique index only_one_yes on mytable
(case when col='YES' then 'YES' end);

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;

Resources