PL/SQL - trigger validating data causes that cannot add any row - oracle

I wrote trigger which is checking if the question has question mark. If not, the error is returned. It doesn't work - even if there is question mark, no data is inserted into db. Please help me to resolve this problem.
create or replace trigger validate_question
before insert on QUESTIONS
for each row
declare
position number(3,0) := -1;
begin
select instr(:new.QUESTION_CONTENT,'?')
into position
FROM QUESTIONS
where QUESTIONID = :new.QUESTIONID;
if pozycja = -1
then
RAISE_APPLICATION_ERROR(-20666, 'This is not a question.');
end if;
end;
Here is how I call it:
set transaction name 'aaa';
insert into QUESTIONS values ('',1,'It should be inserted!?');
commit;

Here is correct implementation of the trigger:
create or replace trigger validate_question
before insert on questions
for each row
begin
if not instr(:new.question_content,'?') > 0
then
raise_application_error(-20666, 'This is not a question.');
end if;
end;
However, a better way of enforcing such rules is with a CHECK CONSTRAINT rather than a trigger:
SQL> drop trigger validate_question
2 /
Trigger dropped.
SQL> alter table questions
2 add constraint questions_content_ck
3 check ( instr(question_content,'?') > 0 )
4 /
Table altered.
SQL> insert into questions values (1,'Is this a question?');
1 row created.
SQL> insert into questions values (2,'This is not a question');
insert into questions values (2,'This is not a question')
*
ERROR at line 1:
ORA-02290: check constraint (APC.QUESTIONS_CONTENT_CK) violated
SQL>

Related

How to rollback a column and its trigger in plsql?

I have a litte task. Firstly I added a column in my table with specific constraints. Then I added a trigger for other jobs.
But I need a rollbacksql and have no idea what to proceed. Can anybody help or give an advice about it? I am adding my sql snippet.
ALTER TABLE FCBSADM.GL_DEF ADD GL_TP NUMBER;
ALTER TABLE FCBSADM.GL_DEF ADD CONSTRAINTS CH_COL CHECK (GL_TP between 1 and 10);
CREATE OR REPLACE TRIGGER GL_DEF_GL_TP_TRG
BEFORE INSERT OR
DELETE OR
UPDATE OF CDATE, CMPNY_DEF_ID, CUSER, DESCR, GL_DEF_ID, MNY_TP_ID, ST, UDATE, UUSER, GL_TP
ON FCBSADM.GL_DEF
FOR EACH ROW
DECLARE
cnt number := 0;
BEGIN
IF INSERTING
THEN
IF :NEW.GL_TP = 2
THEN
SELECT 1 into cnt from dual where exists( select *
FROM LOOKUP_GLCODE_IND_CEZA lookup
WHERE lookup.indirim_glcode = :NEW.gl_Def_id);
IF (cnt = 1) THEN
raise_application_error
(-20101, 'Please insert record into LOOKUP_GLCODE_IND_CEZA before inserting GL_DEF');
END IF;
END IF;
END IF;
END;
What do you want to rollback? Adding a column and creating a trigger? If so, drop them, both.
alter table gl_def drop column gl_tp;
drop trigger gl_def_gl_tp_trg;
A trigger and newly added table can be rolled back only by using drop and alter statements. This is ok if its being done inside a script that executes only a few times. But is highly inefficient if both drop and alter are called frequently for n number of records.

Is before update trigger will fire if same values are updating into a row of column

I am using before update trigger for each row on table, say emp_table to update one column modifid_date before loading into table. If I am going to update the table with same/existing values of a row, then is this trigger going to fire or not?
condition in trigger:
:new.modifid_dt := sysdate;
Table Values before update: john (name),4867 (id),20-04-2016 (modifid_dt)
Table values now going to update: john (name),4867 (id)
Your trigger will be fired, no matter the values you are using; for example:
SQL> create table testTrigger ( a number)
2 /
Table created.
SQL> CREATE OR REPLACE TRIGGER before_update_trigger
2 before update on testTrigger
3 for each row
4 begin
5 dbms_output.put_line('Trigger fired!');
6 end;
7 /
Trigger created.
SQL> insert into testTrigger values (10);
1 row created.
SQL>
SQL>
SQL> update testTrigger set a = 10;
Trigger fired!
1 row updated.
SQL> update testTrigger set a = 11;
Trigger fired!
1 row updated.
SQL>
If you want avoid "false" firing you should write trigger like this:
create or replace trigger trigger1
before update on tst
for each row
begin
IF :new.t_key != :old.t_key AND ... THEN
dbms_output.put_line('Trigger fired!');
END IF;
end;
But beware of NULL values, of course.
New or existing values - no matter, anyway you'll perform an update so trigger will fire.

How do I raise the DUP_VAL_ON_INDEX when user attempts to enter duplicate ID

Yes, I ask numerous questions because I learn more here than from the books. I've created a simple code block that produces desired output but it seems to simple for the current learning block i'm in. Would this code work for anyone that attempts to update the iddonor for a donor table if the id already exists? Haven't learned procedures or functions yet but can guess that would be a more sensible method. Does what i have thus far satisfy and exception handler if a condition arises or should I add more in the declaration? Appreciate the suggestions and learning points if provided.
My Code:
BEGIN
INSERT INTO dd_donor (iddonor)
VALUES (305)
EXCEPTION
WHEN DUP_VAL_ON_INDEX THEN
DBMS_OUTPUT.PUT_LINE('ID already Exists');
END;
DUP_VAL_ON_INDEX exception is raised when you try to store duplicate values in a column that is supported by a unique index.
Let's see a simple example. I have created a table with single column and made it the primary key, which will be supported by an implicit unique index.
Setup
SQL> CREATE TABLE t(ID NUMBER);
Table created.
SQL> ALTER TABLE t ADD CONSTRAINT t_uk PRIMARY KEY(ID);
Table altered.
SQL> INSERT INTO t(ID) VALUES(1);
1 row created.
SQL> COMMIT;
Commit complete.
SQL> SELECT * FROM t;
ID
----------
1
SQL> BEGIN
2 INSERT INTO t(ID) VALUES(1);
3 END;
4 /
BEGIN
*
ERROR at line 1:
ORA-00001: unique constraint (LALIT.T_UK) violated
ORA-06512: at line 2
So, the unique constraint is violated. Let's see how to capture DUP_VAL_ON_INDEX exception:
Test case
SQL> SET serveroutput ON
SQL> BEGIN
2 INSERT INTO t(ID) VALUES(1);
3 EXCEPTION
4 WHEN DUP_VAL_ON_INDEX THEN
5 DBMS_OUTPUT.PUT_LINE('Duplicate value on index');
6 END;
7 /
Duplicate value on index
PL/SQL procedure successfully completed.
SQL>
By the way, the DBMS_OUTPUT was only for demo purpose, ideally you wouldn't have it in your production code.

How to query and execute trigger on the same table

Hope someone can help with this. I am new to triggers and I am trying to create a trigger that checks to see if the record being modified has a specific value.
example
I have a table called Filing that has a filing_id and a filing_status, I want to prevent someone from updating or deleting any records in that table has a filing_status="FILED".
so if i have the following
Filing_id Filing_status Val
--------- ------------- ---
0 Filed X
If someone tried to modify Val the trigger should stop it
I have created the following trigger:
CREATE or replace TRIGGER TRG_PREV_FILING
BEFORE DELETE or UPDATE
ON PF.FILING
FOR EACH ROW
declare
rowcnt number;
BEGIN
SELECT COUNT(filing_id) INTO rowcnt FROM PF.FILING
where status = 'FILED'
and filing_id = :new.filing_id;
if (rowcnt > 0)
then
raise_application_error (-20100, 'You can not delete Or Update initial record');
end if;
END;
The problem I am facing is I am getting:ORA-04091 which is "Table Filing is mutating, Trigger/function may not see it"
So basically I can't query on the same table that I am executing the trigger on? Is that the problem in my case and does anyone know a work around this?
I appreciate any help
You do not have to query the table trigger is firing on to be able to do that kind of check. You can get value of a column that is being modified using :old. Here is an example:
SQL> create table filing(
2 status varchar2(31),
3 val number
4 );
Table created
SQL> create or replace trigger TRG_FILING before delete or update on FILING
2 for each row
3 begin
4 if lower(:old.status) = 'filed'
5 then
6 raise_application_error(-20000, 'You cannot delete or modify this record');
7 end if;
8 end;
SQL> /
Trigger created
SQL> insert into FILING values('FILED', null);
1 row inserted
SQL> insert into filing values('OK', 1);
1 row inserted
SQL> commit;
Commit complete
SQL> select *
2 from filing;
STATUS VAL
------------------------------- ----------
FILED
OK 1
SQL> delete
2 from filing
3 where val is null;
ORA-20000: You cannot delete or modify this record
ORA-06512: at "HR.TRG_FILING", line 4
ORA-04088: error during execution of trigger 'HR.TRG_FILING'
The basic point is that you should design you database in a way that the trigger does its validation based on the updated/deleted row. If you have several rows with the same filing_id then you can overwork you database design. Maybe you really only check against the own table in which case you can use :old. But when you have several rows to check (which I assume because you make a count) then you have to use two tables. Here is a suggestion.
create table filing_status (filing_id number, status varchar2(10));
create table filing_content (filing_id number, content_id number, content varchar2(200));
CREATE or replace TRIGGER TRG_PREV_FILING
BEFORE DELETE or UPDATE
ON FILING_content
FOR EACH ROW
declare
rowcnt number;
BEGIN
SELECT COUNT(filing_id) INTO rowcnt FROM FILING_status
where status = 'FILED'
and filing_id = :new.filing_id;
if (rowcnt > 0)
then
raise_application_error (-20100, 'You can not delete Or update filed record');
end if;
END;
/
insert into filing_status values (1, 'FILING');
insert into filing_content values (1, 1, 'foo');
insert into filing_content values (1, 2, 'bar');
insert into filing_status values (1, 'FILED');
update filing_content set content = 'bahr' where filing_id = 1 and content_id = 2;
ERROR at line 1:
ORA-20100: You can not delete Or update filed record
ORA-06512: at "DEMO.TRG_PREV_FILING", line 9
ORA-04088: error during execution of trigger 'DEMO.TRG_PREV_FILING'

how to fire two oracle insert statement together?Oracle 11g

I am trying to fire two insert statements at a time. Actually i have tried with below query but its inserting in only one table.
EXECUTE IMMEDIATE 'select * from abc.test where test_NAME = ''aaa''' BULK COLLECT INTO T_SC;
IF T_SC.count = 0 THEN
Insert into abc.test (test_ID,test_NAME,status)
VALUES(1,'aaa','a') BULK COLLECT INTO insert_cnt;
IF insert_cnt.count = 1 THEN
INSERT INTO abc.test1(test1_id,test1_NAME,test1_ALIAS,test_ID)
VALUES(1,'bbb','b',1);
COMMIT;
END IF;
it is only inserting in abc.test1 table..What i am going to missing. If anyone knows than plz help me in this.
This whole code of yours doesn't seem right:
why the dynamic sql ?
there are lots of syntax errors
unclosed "if" (as vj shah commented)
missing returning keyword
why do you need the bulk collect if your returning from the insert only one row ?
what is the second "if" for ?
and so on...
Anyway, this code works:
EXECUTE IMMEDIATE 'select * from abc.test where test_NAME = ''aaa''' BULK COLLECT INTO T_SC;
/* BTW, why not
select * bulk collect into T_SC from abc.test where test_NAME = 'aaa';
*/
IF T_SC.count = 0 THEN
Insert into abc.test (test_ID, test_NAME, status)
VALUES(1,'aaa','a') returning test_ID, test_NAME, status BULK COLLECT INTO insert_cnt;
IF insert_cnt.count = 1 THEN
INSERT INTO abc.test1(test1_id,test1_NAME,test1_ALIAS,test_ID)
VALUES(1,'bbb','b',1);
END IF;
COMMIT;
END IF;
Can you explain your problem a little better. Neither your logic nor the data that you show gives any idea of what you are trying to accomplish. (the logic behind the if).
This is also not functional code (too many syntax errors), can you update with the real code you are firing? May be just change the table names?
If you want to make sure both the statements either complete successfully or both of them are rolled back, your approach of including them in a block is correct.
SQL> create table test_rc_2(
2 id number
3 );
Table created.
--Sample 1 : Submitting inserts seperately (only the latest statement is rolled
SQL> insert into test_rc_2 values (100);
1 row created.
SQL> insert into test_rc_2 values ('hello');
insert into test_rc_2 values ('hello')
*
ERROR at line 1:
ORA-01722: invalid number
SQL> commit;
Commit complete.
SQL> select * from test_rc_2;
ID
----------
100
--case 2 : submittig them in a block.
SQL> truncate table test_rc_2
2 ;
Table truncated.
SQL> begin
2 insert into test_rc_2 values(100);
3 insert into test_rc_2 values('hello..');
4 end;
5 /
begin
*
ERROR at line 1:
ORA-01722: invalid number
ORA-06512: at line 3
SQL> commit;
Commit complete.
SQL> select * from test_rc_2;
no rows selected

Resources