Oracle 11g Trigger Issue - sql

I'm a newbie to database and trying to create a trigger which will change a char from "Y" to "N" if another table's tuple is set to 0. I have it working somewhat but it is changing all tuples instead of the single one I want. Here is the trigger and code. Any suggestions gratefully received.
create or replace TRIGGER CHANGE_STOCK_FLAG
AFTER UPDATE OF AMOUNT_REMAINING ON PRODUCT
FOR EACH ROW
BEGIN
UPDATE BOOK
SET IN_STOCK = 'N';
END;
Update statement:
UPDATE PRODUCT
SET AMOUNT_REMAINING = 0
WHERE PROD_ID = 5001;
The trigger compiled OK and on update above resets IN_STOCK to "N" on all tuples in the Book TABLE.
Is there a where clause or something I can use?

Try this:
CREATE OR REPLACE TRIGGER CHANGE_STOCK_FLAG
AFTER UPDATE OF AMOUNT_REMAINING ON PRODUCT
REFERENCING NEW AS NEW OLD AS OLD
FOR EACH ROW
BEGIN
IF (:NEW.AMOUNT_REMAINING=0) THEN
UPDATE BOOK SET IN_STOCK = 'N' WHERE PROD_ID=:NEW.PROD_ID;
END IF;
END;

Related

Update column in another table with trigger

I would like to update a column in another table with the code below but I get a error that the trigger is invalid.
Whats wrong with it?
CREATE OR REPLACE TRIGGER UPDATE_PAYMENT
AFTER INSERT OR UPDATE ON PAYMENT
for each row
begin
update PAYMENTTYPE PT
set PT.PAYMENTTYPECOLUMN = PAYMENT.PAYMENTTYPECOLUMN
where PT.ID = :NEW.ID and PT.ID2 = :NEW.ID2;
end UPDATE_PAYMENT;
In your trigger you refer twice to PAYMENT columns by :NEW., and this is correct, while the third time you use PAYMENT., which is wrong.
The trigger should be:
CREATE OR REPLACE TRIGGER UPDATE_PAYMENT
AFTER INSERT OR UPDATE ON PAYMENT
for each row
begin
update PAYMENTTYPE PT
set PT.PAYMENTTYPECOLUMN = :NEW.PAYMENTTYPECOLUMN -- <------ HERE
where PT.ID = :NEW.ID and PT.ID2 = :NEW.ID2;
end UPDATE_PAYMENT;

Writing a trigger for AFER Update on DB2

I want to set the column EDI_INVOICE to False whenever the DOCUMENT_TYPE is a REBILL for only specific BILL_TO_CODES
This is how I wrote my trigger
CREATE TRIGGER BT_CU_CASS_REBILLS
AFTER UPDATE OF DOCUMENT_TYPE ON TLORDER
REFERENCING OLD AS O NEW AS N
FOR EACH ROW MODE DB2SQL
BEGIN ATOMIC
IF N.DOCUMENT_TYPE <> O.DOCUMENT_TYPE AND N.DOCUMENT_TYPE = 'REBILL'
AND N.BILL_TO_CODE IN (SELECT TRADING_PARTNER FROM EDI_PROFILES WHERE EDI_TYPE = '210' AND EDI_ACTIVE = 'True' AND UPPER(FTP_ADDRESS) LIKE '%CASS%')
THEN SET N.EDI_INVOICE = 'True';
END IF;
END
But when trying to execute the Query to create the trigger I get this Error
SQL0797N The Trigger Lynx.BT_CU_CASS_REBILLS is defined with an unsporrted triggered SQL statement. Line Number = 11. SQLSTATE = 42987
Thank you in advance.
If you want the trigger to change the data in the row for which the trigger is firing, ie.
THEN SET N.EDI_INVOICE = 'True';
you need to use a BEFORE UPDATE trigger.

Oracle 11g Trigger that sets a flag when number below x

I need to create a TRIGGER that sets a flag when a product’s quantity on hand falls below 5.
I've created a table "STP_STOCK" in Oracle 11g and it has the following column:
STP_QUANTITY, NUMBER(4,0), RANGE 0-9999
How do I create a trigger that sets a flag in SQL?
I've got as far as the following... but have no idea re setting a flag.
CREATE OR REPLACE TRIGGER STP_STOCK
AFTER UPDATE
ON orders
FOR STP_QUANTITY
BEGIN
END;
Assuming the flag is in the same table, I would suggest you use a before update trigger. Then you can do something like:
CREATE OR REPLACE TRIGGER STP_STOCK
before UPDATE
ON orders
FOR each row
BEGIN
if :new.stp_quantity < 5
then :new.flag := 'Y';
end if;
END;
(I don't have Oracle on hand to test the syntax, so the syntax might have an error.)
You want to do a before trigger, so you can just set the value in :new. It is bad practice to update the same table in an after trigger.
Presumably, you also want to check if the quantity is larger than 5 and set the flag to 'N', but that is not specified in the question.
Finally, instead of a trigger and a flag, you probably really want to do this with a view or virtual column. Something like:
select o.*, (case when stp_quantity < 5 then 'Y' else 'N' end) as Flag
from orders o
(Note: I'm using * as a convenience. In practice, you would want to list each column in the view.)

Oracle SQL trigger for automatically set a column value

I am writing a Oracle trigger. This trigger should automatically set the value of the column "productId" to be the oid of the row just inserted.
The trigger I wrote is:
create or replace trigger MyProduct_id_trg
after insert on MyProduct
begin
update MyProduct set productId = inserted.oid where oid = inserted.oid;
end;
However, this does not work.
Can someone help me with this?
Regards.
Looks like you are trying to use SQL Server syntax on an Oracle database! Try this:
create or replace trigger MyProduct_id_trg
before insert on MyProduct
for each row
begin
:new.productId := :new.oid;
end;
(Note: before not after, and with for each row.)

Create a trigger that updates a column on one table when a column in another table is updated

i have two tables
Order(id, date, note)
and
Delivery(Id, Note, Date)
I want to create a trigger that updates the date in Delivery when the date is updated in Order.
I was thinking to do something like
CREATE OR REPLACE TRIGGER your_trigger_name
BEFORE UPDATE
ON Order
DECLARE
BEGIN
UPDATE Delivery set date = ??? where id = ???
END;
How do I get the date and row id?
thanks
How do i get the date and row id?
Assuming these are columns on your ORDER table called DELIVERY_DATE and ID your trigger should look something like this:
CREATE OR REPLACE TRIGGER your_trigger_name
BEFORE UPDATE ON Order
FOR EACH ROW
BEGIN
if :new.delivery_date != :old.delivery_date
then
UPDATE Delivery d
set d.delivery_date = :new.delivery_date
where d.order_id = :new.id;
end if;
END;
Note the FOR EACH ROW clause: that is necessary to reference values from individual rows. I have used an IF construct to test whether to execute the UPDATE on Delivery. If you have no other logic in your trigger you could write it like this...
CREATE OR REPLACE TRIGGER your_trigger_name
BEFORE UPDATE OF delivery_date ON Order
FOR EACH ROW
BEGIN
UPDATE Delivery d
set d.delivery_date = :new.delivery_date
where d.order_id = :new.id;
END;
I have answered the question you asked but, as an aside, I will point out that your data model is sub-optimal. A properly normalized design would hold DELIVERY_DATE on only one table: DELIVERY seems teh logical place for it.
Use the OLD and NEW bind variables. OLD references the row or column being updated before the change is made; NEW references it after the change.
CREATE OR REPLACE TRIGGER trig1
BEFORE UPDATE
ON order REFERENCING NEW AS new
FOR EACH ROW
BEGIN
UPDATE delivery
SET ddate = :new.ddate
WHERE id = :new.id;
END;
You can modify the REFERENCING clause to give your bind variables different names. You can include OLD as <name> too. Example:
CREATE OR REPLACE TRIGGER trig1
BEFORE UPDATE
ON order REFERENCING OLD AS old_values NEW AS new_values
...
If you don't want to change the default names of "old" and "new", you can leave out the REFERENCING clause completely.
There is an implicit new and old reference in the trigger in the form of:
REFERENCING OLD AS OLD NEW AS NEW
You can write to the :NEW value but not to the :OLD value.
UPDATE Delivery set date = :new.delivery_date where id = :new.id;
CREATE OR REPLACE TRIGGER "BUR_TABLENAME" BEFORE
UPDATE ON "TABLE" FOR EACH ROW
BEGIN
If :new.active_date is not null Then
:new.active_date := TRUNC(:new.active_date);
End If;
END;
Template:
CREATE OR REPLACE TRIGGER TRIGGER_NAME
BEFORE
UPDATE
ON TABLE_NAME
REFERENCING OLD AS OLD NEW AS NEW
FOR EACH ROW
DECLARE
V_VARIABLE NUMBER (1);
BEGIN
//Do Stuff;
null;
end;
Whenever there is a need for this kind of trigger, have a good look at your design. Is there really a need for a separate delivery record? Does an order really have more than 1 delivery ?
Triggers seem nice but they do tend to mess things up pretty quickly.