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

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.)

Related

PL/SQL - Simple trigger, take from one column and IF-THEN-ELSE to another column

I am trying to figure out where I am going wrong on this simple trigger. I am quite new to triggers and trying to get used to using them with IFTTT statements.
I want the trigger to watch for a new row entry, and if the value is within a certain range within a column (col_a) it will then enter a certain value in the same row, but different column (col_b), which will be NULL up until this is entered. Please can you help?
CREATE TRIGGER trg_test
BEFORE INSERT
ON test_table
FOR EACH ROW
BEGIN
IF :new.col_a >= 10
THEN :new.col_b := 'High';
ELSE
:new.col_b := 'Low';
END IF;
END;
It just keeps coming back with "success with compilation error".
You can easily do this using a virtual column:
alter table test_table
add col_b generated always as (case when col_a >= 10 then 'High' else 'Low' end);
I wish that exercises in triggers used reasonable use-cases. This is not one -- you need both an insert and an update trigger, for instance.

How to write a trigger that checks an updated value in Oracle?

For an assignment I need to write an Oracle SQL trigger that prevents the StdBalance column in the STUDENT table from exceeding 500. Normally I would just use a check constraint to enforce this however I am being forced to write a trigger for it. As expected Oracle is throwing a mutating error due to me using SELECT in an update trigger and will not let me update the StdBalance value with anything. Does anyone have any idea how I could work around this? Here is the code for the trigger.
CREATE OR REPLACE TRIGGER Balance_Trigger
BEFORE UPDATE ON STUDENT
FOR EACH ROW
DECLARE
Current_Balance NUMBER;
BEGIN
SELECT :new.StdBalance
INTO Current_Balance
FROM STUDENT
WHERE :new.stdID = StdID;
IF Current_Balance > 500
THEN Raise_Application_error(-20007, 'You cannot exceed an unpaid balance of $500');
end if;
end;
/
show error;
Just use :
Current_Balance := :new.StdBalance;
Instead of
SELECT :new.StdBalance
INTO Current_Balance
FROM STUDENT
WHERE :new.stdID = StdID;
to suppress the mutating error.
P.S. Even if such assignments are used in these cases, as David Faber warned, there's no need to return a value for Current_Balance, :new.StdBalance may be used directly in comparison for IF :new.StdBalance > 500 ....

Wondering why my SQL statement is ignoring my SET symbol

This is my SQL trigger and it is suppose to change the reorder value to Y or N depending if ON_HAND is less than or greater than the MINIMUM. The problem is it's ignoring the set statement completely. Do I have to arrange these differently?
CREATE OR REPLACE TRIGGER TRG_REORDER
AFTER UPDATE OF ON_HAND, MINIMUM ON PART
BEGIN
IF ON_HAND <= MINIMUM THEN
SET REORDER = 'Y';
ELSE ON_HAND > MINIMUM
SET REORDER = 'N';
END IF;
END;
Trigger bodies use PL/SQL syntax, not SQL. So for assignment you need := not set.
Your code has some other syntax errors.
You need to refer to the :new values of the columns.
You don't need a condition in the ELSE clause.
In order to modify the values of columns in a trigger, it must be a BEFORE trigger and fire FOR EACH ROW.
So fixing all that, this should now work for you (caveat: untested code).
CREATE OR REPLACE TRIGGER TRG_REORDER
before UPDATE OF ON_HAND, MINIMUM ON PART
for each row
BEGIN
IF :new.ON_HAND <= :new.MINIMUM THEN
:new.REORDER = 'Y';
ELSE
:new.REORDER = 'N';
END IF;
END;
I don't know Oracle triggers but I suspect you want a BEFORE trigger and an assignment that looks something like this.
:new.REORDER := case when :new.ON_HAND <= :new.MINIMUM then 'Y' else 'N' end;
Check here to get started:
http://www.techonthenet.com/oracle/triggers/before_update.php

how to write Instead of update? - Trigger

I have table A and there is a column name COL_A.
I want that if someone change the value, lets say from 1 to 'X' (not costant) that the trigger will change it back from 'X' to 1.
SQLite does not support changing the new column values.
The only way to change a column in a trigger would be to run an UPDATE command,
but that would run the trigger again.
What you can do is to prevent changing the column in the first place:
CREATE TRIGGER IF NOT EXISTS prevent_col_a_change
BEFORE UPDATE OF col_a ON a
BEGIN
SELECT RAISE(ABORT, 'COL_A must not be changed');
END;
UPDATE trigger is a good solution for your case. Just set old value to the new value, that will lead to behaviour you want.
For example:
CREATE OR REPLACE TRIGGER orders_before_update
BEFORE UPDATE
ON orders
FOR EACH ROW
BEGIN
:new.CreatedAt:= :old.CreatedAt;
END;

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.