How to insert a record into multiple tables using a trigger? - sql-server-2005

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;

Related

What is the right prototype for my SQL code?

I am new in learning SQL and I am trying to apply a trig on those two tables by using SQLcl:
prodc
( PRODC_NAME, DISCOUNTED CHAR(1) DEFAULT 'N',
PK PRIMARY KEY (PRODC_NAME));
peopleOrder
( ORDERID, PRODC_NAME,
PRIMARY KEY (ORDERID, PRODC_NAME),
FOREIGN KEY (PRODC_NAME) REFERENCES PRODC (PRODC_NAME));
I want my trig to do the following:
when I update or insert rows to peopleOrder, the trig should check if a row's product_name has value 'N' in the discounted column that is located in the product table; if it has no 'N' value, it should show an error message.
I tried many ways and the following trig, but when I insert rows, the trig seems to not be working and have no effect on the rows:
CREATE OR REPLACE TRIGGER constraint_1
After UPDATE OR INSERT on peopleOrder
for each row
begin
if not (:new.prodc_name in
(select prodc_name from prodc where discounted = 'N' )) then
RAISE_ERROR(-30001, 'No product can be ordered
!');
END IF;
INSERT INTO peopleOrder VALUES (:new.ORDERID, :new.PRODC_NAME);
END;
/
My insert command is:
INSERT INTO peopleOder (ORDERID, PRODC_NAME)
VALUES (251, 'Puton');
and 'Puton' has value 'N' in the discounted column in the prodc table.
The first thing you need is to understand what a trigger is. It is a piece of code that runs as part of the statement causing it to fire. For this reason you cannot reference the table causing it to fire. Normally that is completely unnecessary anyway. Every row trigger has access to to 2 rows: a copy of the existing data (old) and the resulting data (new). Update having both filled and Insert/Delete just new/old as appropriate for the action. Before statement triggers can modify the new data, after triggers cannot. Those rows allow you to process the columns in the table without DML or select on it. (However you cannot 'scan' the table). At any level a trigger may raise an exception which halts the entire process and the invoking statement. If no exception is raised then processing the invoking proceeds. For a more complete description see PL/SQL Language Reference or the version of Oracle you are running.
In this case your trigger breaks down to a single if
statement.
-- Revised. Orig missed that flag comming from different table.
create or replace trigger constraint_1
before update or insert on peopleOrder
for each row
declare
dis_num integer;
begin
select count(*)
into dis_num
from product
where discounted != 'N'
and product_name = :new.product_name
and rownum < 2;
if dis_num != 0 then
raise_application_error(-20001, 'No discounted product can be ordered!');
end if;
end constraint_1;
-- Orig ==============================================
CREATE OR REPLACE TRIGGER constraint_1
before UPDATE OR INSERT on peopleOrder
for each row
begin
if :new.discounted = 'N' then
RAISE_APPLICATION_ERROR(-20001, 'No discounted product can be ordered')
end if;
END;
/

Updating the record of same table when new record is inserted or updated in oracle

I am new to learning Oracle. I have a task in which I need to update value of any previous record if new record contains its reference.
Table structure is as below :
Review_Table
(review_id number pk,
review_name varchar2,
previous_review number null,
followup_review number null
)
Here previous_review and followup_review columns are objects of same table i.e Review_table.
Now consider we have two records in Review_table A and B, A does not have any previous or followup review. When user creates/updates the record B and he selects record A as previous record, then we want to automatically update (via trigger) the value of A record's followup review with B's Review ID.
I have tried writing following trigger
create or replace trigger "REVIEW_T1"
AFTER insert or update on "REVIEW_TABLE"
for each row
begin
update REVIEW_TABLE
set review_follow_up_review = :new.REVIEW_ID
where REVIEW_ID = :new.REVIEW_PREVIOUS_REVIEW;
end;
But I am getting error as : REVIEW_TABLE is mutating, trigger/function may not see it ORA-06512
I have tried searching everything but was unable to find any solution for it
TL;DR: No trigger, no mutating. Do not use trigger to change another row in the same table.
I absolutely agree with #StevenFeuerstein's comment:
I also suggest not using a trigger at all. Instead, create a package that contains two procedures, one to insert into table, one to update. And within these procedures, implement the above logic. Then make sure that the only way developers and apps can modify the table is through this package (don't grant privs on the table, only execute on the package).
Take a look at the following example.
Prepare the schema:
create table reviews (
id number primary key,
name varchar2 (32),
previous number,
followup number
);
create or replace procedure createNextReview (name varchar2, lastId number := null) is
lastReview reviews%rowtype;
nextReview reviews%rowtype;
function getLastReview (lastId number) return reviews%rowtype is
begin
for ret in (
select * from reviews where id = lastId
for update
) loop return ret; end loop;
raise_application_error (-20000, 'last review does not exist');
end;
procedure insertReview (nextReview reviews%rowtype) is
begin
insert into reviews values nextReview;
exception when others then
raise_application_error (-20000, 'cannot insert next review');
end;
procedure setFollowUp (nextId number, lastId number) is
begin
update reviews set
followup = nextId
where id = lastId
;
exception when others then
raise_application_error (-20000, 'cannot update last review');
end;
begin
if lastId is not null then
lastReview := getLastReview (lastId);
end if;
nextReview.id := coalesce (lastReview.id, 0)+1;
nextReview.name := name;
nextReview.previous := lastId;
insertReview (nextReview);
if lastReview.Id is not null then
setFollowUp (nextReview.id, lastReview.Id);
end if;
exception when others then
dbms_output.put_line (
'createNextReview: '||sqlerrm||chr(10)||dbms_utility.format_error_backtrace ()
);
end;
/
Execute:
exec createNextReview ('first review')
exec createNextReview ('next review', 1)
See the outcome of work done:
select * from reviews;
ID NAME PREVIOUS FOLLOWUP
---------- ---------------- ---------- ----------
1 first review 2
2 next review 1
First you need to read about triggers, mutating table error and compound triggers: http://docs.oracle.com/cd/E11882_01/appdev.112/e25519/triggers.htm#LNPLS2005
Your trigger is AFTER UPDATE OR INSERT. Means if you run UPDATE OR INSERT statements on this table, the trigger will fire. But you are trying to update the same table again inside your trigger, which is compl. wrong.
I think you can fix this by rewriting this as a before trigger, rather than an after trigger.

Outside table reference in trigger

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;

need to write a trigger

I want to write a trigger for a table "TRANSACTION".When a new line is inserted, I want to trigger to update the field "TRANSACTIONID" to the maximum + 1 of all the previous records.
I on't know much about SQL. Can someone help me?
many thanks
This is a really bad idea for a multi-user environment, as it will serialise inserts into the table. The usual approach is to use an Oracle sequence:
create sequence transaction_seq;
create trigger transaction_bir before insert on transaction
for each row
begin
:new.id := transaction_seq.nextval;
end;
To write a trigger based solution that actually got the max current value plus 1, you would need to write a complex 3-trigger solution to avoid the "mutating table" issue. Or you could create a simpler solution using another table to hold the current maximum value like this:
create table transaction_max (current_max_id number);
insert into transaction_max values (0);
create trigger transaction_bir before insert on transaction
for each row
declare
l_current_max_id number;
begin
update transaction_max set current_max_id = current_max_id + 1
returning current_max_id into l_current_max_id;
:new.id := l_current_max_id;
end;
This will avoid the mutating table issue and will serialize (slow down) inserts, so I don't see any advantage of this over using a sequence.
CREATE TRIGGER trigger1 on TransactionTable
INSTEAD OF INSERT
AS
BEGIN
DECLARE #MaxTranId INT
SELECT
#MaxTranId = MAX(TransactionId)
FROM
TransactionTable
INSERT INTO TransactionTable
SELECT
#MaxTranId + 1 ,
RestOfYourInsertedColumnsHere ,
FROM
inserted
END
GO

MySQL trigger issue

I got this trigger, I want to evaluate the mobile phone and insert into another table if the regexp returns a value. I've tried with this but not success.
delimiter //
create trigger companyA_phones after insert on customer
for each row
begin
set #phone = (select new.phone from customer where new.phone regexp '^0416');
if (#phone) then
insert into company_A(new.id, #phone);
end if;
end//
You don't make it entirely clear what trouble you are having, but I don't think you need to be selecting the .new values like that -- as they are already available to you. Try something like this:
CREATE TRIGGER companyA_phones
AFTER INSERT ON customer
FOR EACH ROW
BEGIN
IF (new.phone REGEXP '^0416' AND new.id IS NOT NULL) THEN
INSERT INTO company_A (customerid, phone)
VALUES (new.id, new.phone);
END IF;
END
The need for this trigger does seem to suggest that your underlying schema design is not correctly normalised, so you might want to think about that too.