Outside table reference in trigger - sql

I am using MariaDB as my database and I am running into some issues creating a trigger. The code is below:
CREATE TRIGGER `trigger` BEFORE INSERT ON `table_1` FOR EACH ROW
BEGIN
IF NOT CONTAINS(`db`.`table_2`.`item`, NEW.item) THEN
INSERT INTO `db`.`table_2` (`item`, `item_2`, `item_3`) VALUES (NEW.item, "foo",
"bar");
END IF;
END
The issue is that table_2 is in the database "db" along with table_1 but when this code is run, it gives me the error below:
SQL Error (1109): Unknown table 'table_2' in field list
I am very confused by this because it seems like I should be able to do this by everything I am reading. All I am trying to do is force an insert in one table to cause an insert into another table if the condition is not met.

I am guessing that you intend:
CREATE TRIGGER `trigger` BEFORE INSERT ON `table_1` FOR EACH ROW
BEGIN
IF NOT EXISTS (SELECT 1 FROM db.table_2 t2 WHERE CONTAINS(t2.item, NEW.item) THEN
INSERT INTO `db`.`table_2` (`item`, `item_2`, `item_3`)
VALUES (NEW.item, 'foo', 'bar');
END IF;
END;

Related

PostgreSQL, check for duplicate before insert

I'm running PostgreSQL 10 and have several BEFORE INSERT OR UPDATE and AFTER INSERT OR UPDATE on my table tests.
I want to have another trigger BEFORE INSERT OR UPDATE which should check for potential duplicate row.
I've made this:
CREATE OR REPLACE FUNCTION set_check_dublicate_on_test() RETURNS trigger AS $$
BEGIN
IF EXISTS (SELECT 1 FROM tests WHERE test_id = NEW.test_id) THEN
RETURN NULL;
ELSE
RETURN NEW;
END IF;
END;
$$ LANGUAGE plpgsql;
DROP TRIGGER IF EXISTS set_check_dublicate_on_test ON tests;
CREATE TRIGGER set_check_dublicate_on_test BEFORE INSERT OR UPDATE ON tests
FOR EACH ROW EXECUTE PROCEDURE set_check_dublicate_on_test();
But I'm not sure if it will conflict with other triggers or it will fullfill the goal, and the triggers simply will be ignored if this returns NULL ?
Firstly - I believe that if you want to have a unique field in your table - then it is the easiest to mark it as such:
https://www.postgresql.org/docs/current/ddl-constraints.html#DDL-CONSTRAINTS-UNIQUE-CONSTRAINTS
If an attempted insert on such a field should not raise an error, then there is a the ON CONFLICT keyword:
https://www.postgresql.org/docs/current/sql-insert.html
Especially: ON CONFLICT DO NOTHING
Let the database manage uniqueness! This ensures data integrity for both inserts and updates.
This is quite simple:
alter table test add constraint unq_test_test_id unique (test_id);
If you insert rows one at a time, then this is fine. The insert (or update) will fail.
If you want to insert multiple rows and allow non-duplicate inserts to go in, then us on conflict:
insert into test ( . . . )
select . ..
from . . .
on conflict on constraint unq_test_test_id do nothing;

Values of the inserted row in a Trigger Oracle

I want a trigger that updates the value of a column, but I just want to update a small set of rows that depends of the values of the inserted row.
My trigger is:
CREATE OR REPLACE TRIGGER example
AFTER INSERT ON table1
FOR EACH ROW
BEGIN
UPDATE table1 t
SET column2 = 3
WHERE t.column1 = :new.column1;
END;
/
But as I using FOR EACH ROW I have a problem when I try it, I get the mutating table runtime error.
Other option is not to set the FOR EACH ROW, but if I do this, I dont know the inserted "column1" for comparing (or I dont know how to known it).
What can I do for UPDATING a set of rows that depends of the last inserted row?
I am using Oracle 9.
You should avoid the DML statements on the same table as defined in a trigger. Use before DML to change values of the current table.
create or replace trigger example
before insert on table1
for each row
begin
:new.column2 := 3;
end;
/
You can modify the same table with pragma autonomous_transaction:
create or replace trigger example
after insert on table1 for each row
declare
procedure setValues(key number) is
pragma autonomous_transaction;
begin
update table1 t
set column2 = 3
where t.column1 = key
;
end setValues;
begin
setValues(:new.column1);
end;
/
But I suggest you follow #GordonLinoff answere to your question - it's a bad idea to modify the same table in the trigger body.
See also here
If you need to update multiple rows in table1 when you are updating one row, then you would seem to have a problem with the data model.
This need suggests that you need a separate table with one row per column1. You can then fetch the value in that table using join. The trigger will then be updating another table, so there will be no mutation problem.
`create table A
(
a INTEGER,
b CHAR(10)
);
create table B
(
b CHAR (10),
d INTEGER
);
create trigger trig1
AFTER INSERT ON A
REFERENCING NEW AS newROW
FOR EACH ROW
when(newROW.a<=10)
BEGIN
INSERT into B values(:newROW.b,:newROW.a);
END trig1;
insert into A values(11,'Gananjay');
insert into A values(5,'Hritik');
select * from A;
select * from B;`

Instead of trigger , insert on view

I have this view
CREATE VIEW NaveTiconderoga AS
SELECT nume, tip, cate_arme, diametru_tun, deplasament, Nave.clasa, anul_lansarii
FROM Clase, Nave
WHERE Clase.clasa = Nave.Clasa AND Nave.Clasa = 'Ticonderoga';
I wish to create a trigger to allow inserting through this view.
I wrote the following code, but i'm sure that it isn't correct as far as the WHERE clause from the SELECT.
Any pointers please?
CREATE OR REPLACE TRIGGER ticonderoga
instead of insert on NaveTiconderoga
referencing new as new old as old
begin
insert into clase (clasa, tip, cate_arme, diametru_tun, deplasament)
values (:new.clasa, :new.tip, :new.cate_arme, :new.diametru_tun, :new.deplasament);
insert into nave (nume, clasa, anul_lansarii)
values (:new.nume, :new.clasa, :new.anul_lansarii);
end;
If you want to restrict the value inserted into the view (and thus the underlying tables), so you can't put in something that the view itself won't show, you can't use a check constraint; but you can test the value inside the trigger and throw an exception if you see something you don't like:
CREATE OR REPLACE TRIGGER ticonderoga
instead of insert on NaveTiconderoga
referencing new as new old as old
begin
if :new.clasa is null or :new.clasa != 'Ticonderoga' then
raise_application_error(-20001, 'Invalid clasa');
end if;
insert into clase (clasa, tip, cate_arme, diametru_tun, deplasament)
...
SQL Fiddle of what I think you're worried about. If you change the trigger in that to:
create trigger tr42
instead of insert on v42
begin
if :new.id != 1 then
raise_application_error(-20001, 'Invalid ID');
end if;
insert into t42 (id) values (:new.id);
end;
/
... then the second insert will fail. I think that is what you want to happen, anyway.

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)

How to insert a record into multiple tables using a trigger?

I have two Tables.
I want to insert the same record on both tables at the same time.
I.e., while I insert a record for the first table, this same record also is inserted in the second table using a trigger.
Do you have any experience/advice in this process ?
if you're using stored procedures you can easily manage this
CREATE PROCEDURE sp_Insert
#Value varchar(10)
AS
insert into table1 (...,...) values (#value,...)
insert into table2 (...,...) values (#value,...)
I would suggest using Erik's method over a trigger. Triggers tend to cause performance issues, and a lot of times, you forget that the trigger exists, and get unexpected behavior. If you do want to use a trigger however, it will work. here is an example:
CREATE TRIGGER trgTest ON Test
FOR INSERT
AS
INSERT Test2
(Id, value)
SELECT Id, Value
FROM Inserted
Can Use Cursor Concept!
CREATE OR REPLACE TRIGGER bi_order
BEFORE INSERT
ON ord
REFERENCING OLD AS OLD NEW AS NEW
FOR EACH ROW
WHEN (NEW.payment_type = 'CREDIT')
DECLARE
CURSOR cur_check_customer IS
SELECT 'x'
FROM customer
WHERE customer_id = :NEW.customer_id
AND credit_rating = 'POOR';
lv_temp_txt VARCHAR2(1);
lv_poor_credit_excep EXCEPTION;
BEGIN
OPEN cur_check_customer;
FETCH cur_check_customer INTO lv_temp_txt;
IF (cur_check_customer%FOUND) THEN
CLOSE cur_check_customer;
RAISE lv_poor_credit_excep;
ELSE
CLOSE cur_check_customer;
END IF;
EXCEPTION
WHEN lv_poor_credit_excep THEN
RAISE_APPLICATION_ERROR(-20111, 'Cannot process CREDIT ' ||
'order for a customer with a POOR credit rating.');
WHEN OTHERS THEN
RAISE_APPLICATION_ERROR(-20122, 'Unhandled error occurred in' ||
' BI_ORDER trigger for order#:' || TO_CHAR(:NEW.ORDER_ID));
END bi_order;