how to insert 3 rows as per my conditions with pl/sql code - sql

i have to insert 3 rows in a table as per my conditions.
let's assume 3 insert statement are insert A, insert B, insert C.
if INSERT A success then automatically INSERT C also should be executed and as well as INSERT C success then automatically insert A should be executed.
if both A & C failed then only insert B should be executed.

This is what I meant (while discussing it with #XING); don't mind WHEN OTHERS, it just shows that something will need to be handled.
begin
insert into A values (1); --> if this succeeds,
insert into B values (1); --> insert into B will automatically follow
exception
when others then --> if anything goes wrong above
insert into C values (1); --> insert into C will be done.
end; --> But, what if it fails? Could that happen?
--> If so, it'll have to be handled as well.

Related

Insert into the same table where the trigger (before insert) is executed

I have to do a trigger that have to write the same column twice but with one different value, example:
The before insert statement is:
BEFORE INSERT ON MXGLCOMP_CLOUD
The data I received is: 12345, RAIL, 075, HDFG
But also, I want to insert into MXGLCOMP_CLOUD the same data but like this:
12345, RAIL, 069, HDFG.
I wrote the following code but I'm afraid that the trigger will fall into a infinite loop due the insert I do in the same trigger.
create or replace TRIGGER MXGLCOMP_CLOUD_TRG
BEFORE INSERT ON MXGLCOMP_CLOUD
REFERENCING OLD AS OLD NEW AS NEW
FOR EACH ROW
BEGIN
INSERT INTO MXGLCOMP_CLOUD (ACTIVE, COMPTEXT, COMPVALUE, EXTERNALREFID)
VALUES (:NEW.ACTIVE, :NEW.COMPTEXT, '069', :NEW.EXTERNALREFID);
END;
Is this ok? What I have to do? As I said before, I didn't run the test because I don't want that infinite loop.
As you already suspect, your current code will loop because the insert inside the trigger will cause the trigger to fire again, and that will do another insert, which will cause the trigger to fire, which will ... etc. But Oracle will terminate when it spots that happening, indirectly:
ORA-00036: maximum number of recursive SQL levels (50) exceeded
ORA-06512: at "SCHEMA.MXGLCOMP_CLOUD_TRG", line 7
Avoiding that is simple in this case: just check the value being inserted and only insert another new row if it's '075':
create or replace trigger mxglcomp_cloud_trg
before insert on mxglcomp_cloud
for each row
begin
if :new.compvalue = '075' then
insert into mxglcomp_cloud(active, comptext, compvalue, externalrefid)
values(:new.active, :new.comptext, '069', :new.externalrefid);
end if;
end;
/
Then a single insert into an empty table creates two rows:
insert into mxglcomp_cloud (active, comptext, compvalue, externalrefid)
values (12345, 'RAIL', '075', 'HDFG');
1 row inserted.
select * from mxglcomp_cloud;
ACTIVE COMPTEXT COM EXTERNALRE
---------- ---------- --- ----------
12345 RAIL 069 HDFG
12345 RAIL 075 HDFG
However I still don't think this is a good idea, You are hiding business logic and data manipulation and there will be side-effects that users may not expect. Just as an obvious example, the insert reported "1 row inserted" when there were really two, which is confusing.
It would be better to perform two inserts from the application layer, or to put both in a procedure and make the application (and everyone else) call that.
If you actually want to change 'GB' into two rows, one with '075' and one with '069', then you can do the same thing but test for 'GB' and change its value to '075', while still inserting the extra row:
create or replace trigger mxglcomp_cloud_trg
before insert on mxglcomp_cloud
for each row
begin
if :new.compvalue = 'GB' then
-- change this row from GB to 075
:new.compvalue := '075';
-- add another row for 069
insert into mxglcomp_cloud(active, comptext, compvalue, externalrefid)
values(:new.active, :new.comptext, '069', :new.externalrefid);
end if;
end;
/
then (starting from an empty table again):
insert into mxglcomp_cloud (active, comptext, compvalue, externalrefid)
values (12345, 'RAIL', 'GB', 'HDFG');
1 row inserted.
select * from mxglcomp_cloud;
ACTIVE COMPTEXT COM EXTERNALRE
---------- ---------- --- ----------
12345 RAIL 069 HDFG
12345 RAIL 075 HDFG

How to allow oracle table column to have multiple rows in column but sames values only. Using Constraints

How to allow oracle table column to have multiple rows in column but same value only.
Create Table test ( col int);
case - I
insert into test values (1);
--should work
insert into test values (1);
--should work
insert into test values (2);
--Should throw error !!!!
case - II
truncate table test;
insert into test values (2);
--should work
insert into test values (2);
--Should work
insert into test values (1);
--Should throw error !!!!!!
If I have understood your requirement correctly, you can use before insert trigger. Check the value present in table, if new value matches with table value or table is having no data then only allow insert.
Here's the link about trigger
http://docs.oracle.com/cd/B19306_01/appdev.102/b14251/adfns_triggers.htm
UPDATE
Based on OP's two cases, I think a BEFORE INSERT TRIGGER would do the job:
Test case:
SQL> DROP TABLE TEST PURGE;
Table dropped.
SQL>
SQL> CREATE TABLE test
2 ( col INT
3 );
Table created.
SQL>
SQL> CREATE OR REPLACE TRIGGER trg BEFORE
2 INSERT ON TEST FOR EACH ROW DECLARE ID NUMBER;
3 BEGIN
4 BEGIN
5 SELECT DISTINCT col INTO ID FROM TEST;
6 EXCEPTION
7 WHEN no_data_found THEN
8 NULL;
9 END;
10 IF :NEW.col <> id THEN
11 RAISE_APPLICATION_ERROR(-20001, 'Cannot Insert different value in the table');
12 END IF;
13 END;
14 /
Trigger created.
SQL>
The NO_DATA_FOUND exception is to ignore the first insert, since there would be no rows before that.
Now, let's test the INSERT statements:
CASE 1
SQL> INSERT INTO TEST VALUES (1);
1 row created.
SQL>
SQL> INSERT INTO TEST VALUES (1);
1 row created.
SQL>
SQL> INSERT INTO TEST VALUES (2);
INSERT INTO TEST VALUES (2)
*
ERROR at line 1:
ORA-20001: Cannot Insert different value in the table
ORA-06512: at "LALIT.TRG", line 10
ORA-04088: error during execution of trigger 'LALIT.TRG'
SQL>
CASE 2
SQL> TRUNCATE TABLE TEST;
Table truncated.
SQL>
SQL> INSERT INTO TEST VALUES (2);
1 row created.
SQL>
SQL> INSERT INTO TEST VALUES (2);
1 row created.
SQL>
SQL> INSERT INTO TEST VALUES (1);
INSERT INTO TEST VALUES (1)
*
ERROR at line 1:
ORA-20001: Cannot Insert different value in the table
ORA-06512: at "LALIT.TRG", line 10
ORA-04088: error during execution of trigger 'LALIT.TRG'
SQL>

How to 'remember' a value to insert into two tables in sqlite?

I have a trigger that I want to insert the same random value into two tables. How do I do this?
CREATE TRIGGER insertTrigger AFTER INSERT ON TableAB
BEGIN
INSERT INTO TableA(id, num) VALUES(RANDOM(), 1);
INSERT INTO TableB(id, num) VALUES(??, 1);
END;
I am not really using Random, but my own custom sqlite function which essentially does the same thing, but I need to remember that value to insert into TableB. How do I do that?
SQLite has no such thing as variables, but you could read the value from the record that you had just inserted into the first table:
CREATE TRIGGER insertTrigger
AFTER INSERT ON TableAB
BEGIN
INSERT INTO TableA(id, num) VALUES(RANDOM(), 1);
INSERT INTO TableB(id, num) SELECT id, 1
FROM TableA
WHERE rowid = last_insert_rowid();
END;

trigger failed -ORA-04098 is invalid and failed re-validation sql

create or replace trigger "STUDENT_PERSONAL_DETAIL_T1"
AFTER insert or update or delete on "STUDENT_PERSONAL_DETAIL"
for each row
begin
insert into fa1 (s_id,name,class,sec)
select reg_no,name,class,sec
from inserted
end;
This is the trigger created using Oracle xe trigger creating interface.
It is created without error but when a insert is called on the table trigger error is shown
trigger failed -ORA-04098 is invalid and failed re-validation.
Guidance and suggestions will help a lot.
You should use:
REFERENCING new AS new
...
BEGIN
INSERT INTO fa1(s_id, name, class, sec)
VALUES (:new.reg_no, :new.name, :new.class, :new.sec);
...
see, this select statement is invalid, because there is no such table as inserted
select reg_no,name,class,sec
from inserted
EDIT if you want to log the inserted values into table fa1, you would do something like, if you had the following columns in table STUDENT_PERSONAL_DETAIL: reg_no,name,class,sec
create or replace trigger "STUDENT_PERSONAL_DETAIL_T1"
AFTER insert on "STUDENT_PERSONAL_DETAIL"
for each row
begin
insert into fa1 (s_id,name,class,sec)
values (:new.reg_no, :new.name, :new.class, :new.sec)
end;
Note the clause AFTER insert on "STUDENT_PERSONAL_DETAIL". I have omitted or update or delete to make sure this will only be triggered for newly inserted records. (because you tried to select from table 'inserted', I have concluded that's what you want to do)

Oracle SQL Multiple Insert Ignore duplicate rows

I was wondering what would be the preferred technique in Oracle to copy multiple records into a database that ignored duplicate values on a certain index. the statements are stated explicitly in the statement and don't come from another table
INSERT INTO EXAMPLE (A, B, C, D) VALUES (null,'example1','example2',EXAMPLE_SEQ.nextval);
INSERT INTO EXAMPLE (A, B, C, D) VALUES (null,'example2','example3',EXAMPLE_SEQ.nextval);
INSERT INTO EXAMPLE (A, B, C, D) VALUES (null,'example4','example5',EXAMPLE_SEQ.nextval);
I am currently doing it like this and checking manually, but need to find a way so that these can be handled as scripts
If you've decided to stick with INSERTs you can prevent insertion of duplicate rows by using constraints whether it primary key or unique key. If it happens to violate a unique constraint your script will stop and you'll have to roollback all changes made by previous inserts(unless you have committed every single of them). To handle that exception you could write a similar pls/sql block.
declare
l_unique_exception exception;
pragma exception_init(l_unique_exception, -1);
begin
insert into test(id, test_vector)
values(1, 123);
insert into test(id, test_vector)
values(1, 123);
......
Insert into
commit;
exception
when l_unique_exception
then process the exception;
end;
IN ADDITION
If you want to proceed after one of the inserts raises an exception then the following example might be in handy.
Create a table that going to contain errors. For example.
CREATE TABLE tb_errors (
ErrorTag varchar2(123)
)
Provide an error logging invoking CREATE_ERROR_LOG procedure of DBMS_ERRLOG package
DBMS_ERRLOG.CREATE_ERROR_LOG('YourDmlTable. Test in this case', 'tb_errors');
Add log errors into clause to each insert
Here is an example
declare
begin
insert into test(id, col1)
values(1, 123)
log errors into tb_errors('simple expression') reject limit unlimited;
insert into test(id, col1)
values(1, 123)
log errors into tb_errors('simple expression') reject limit unlimited;
insert into test(id, col1)
values(1, 123)
log errors into tb_errors('simple expression') reject limit unlimited;
commit;
end;
After your script is completed you can query error logging table, tb_errors in this case, to see what went wrong.
You should look at the MERGE syntax.
http://en.wikipedia.org/wiki/Merge_(SQL)
merge example target
using (select 1 as id, 'a' as val) as source
on source.id = target.id
and source.val = target.val
when not matched then
insert (id, val) values (source.id, source.val);
I suggest you to use LOG error clause if you have a goal to provide additional treatment of incorrect data. Please consider http://www.oracle-base.com/articles/10g/dml-error-logging-10gr2.php - good example is there.