I am using Oracle Apex.
I need to create a trigger for checking the no. of stock whether < 0.
If the no. of stock < 0 then insert action is stopped then prompt a alert message to user.
Below coding dose not work. what is wrong of my code? please help.
My coding:
CREATE OR REPLACE TRIGGER cw_service_b4_trigger
BEFORE INSERT ON cw_serviceline
FOR EACH ROW
DECLARE
exist_stock number;
BEGIN
select stock into exist_stock from cw_inventory where inv_id = :new.inv_id;
if (exist_stock - :new.quantity) < 0 then
dbms_output.put_line ('Out of Stock');
return;
end if;
END;
/
You haven't thrown any sort of error. All your trigger does is output a message.
return doesn't cause the INSERT to stop, it just causes the trigger logic to return.
Instead you need to raise an error to cause the insert to fail.
if exist_stock < :new.quantity then
raise_application_error(-20000, 'Out of stock');
end if;
Related
Hello fellow programmers and happy new year to you all!
I have few university tasks for winter break and one of them is to create trigger on table:
PERSON(ID, Name, Surname, Age);
Trigger is supposed to inform user when they have inserted row with invalid ID. Vadility criteria is that ID is 11 digits long.
I tried to write solution like this:
CREATE OR REPLACE TRIGGER person_id_trigg
AFTER INSERT
ON person
DECLARE
idNew VARCHAR(50);
lengthException EXCEPTION;
BEGIN
SELECT id INTO idNew FROM INSERTED;
IF LENGTH(idNew) <> 11 THEN
RAISE lengthException;
END IF;
EXCEPTION
WHEN lengthException THEN
dbms_output.put_line('ID for new person is INVALID. It must be 11 digits long!');
END;
Then I realized that INSERTED exists only in sqlserver and not in oracle.
What would you suggest I could do to fix that?
Thanks in advance!
Do you want to raise an exception (which would prevent the insert from succeeding)? Or do you want to allow the insert to succeed and write a string to the dbms_output buffer that may or may not exist and may or may not be shown to a human running the insert?
In either case, you'll want this to be a row-level trigger, not a statement-level trigger, so you'll need to add the for each row clause.
CREATE OR REPLACE TRIGGER person_id_trigg
AFTER INSERT
ON person
FOR EACH ROW
If you want to raise an exception
BEGIN
IF( length( :new.id ) <> 11 )
THEN
RAISE_APPLICATION_ERROR( -20001,
'The new ID value must have a length of 11' );
END IF;
END;
If you want to potentially print output but allow the insert to succeed
BEGIN
IF( length( :new.id ) <> 11 )
THEN
dbms_output.put_line( 'The new ID value must have a length of 11' );
END IF;
END;
Of course, in reality, you would never use a trigger for this sort of thing. In the real world, you would use a constraint.
I would like to create a trigger that store Who(Names) as the Loged User, Action as what he/she has done, And the Time he/she made it. But Also it should be capable of revolking the changes when it's not Working Time for example working time can be (from 8H:00 AM to 05:00 PM). So Tried to create it.
// This is the Table to Store the Log named "System_events"
create table system_events (who varchar2(10),action varchar2(10), when date);
Actually the trigger will check and save any change on a table named students
//Codes to create that trigger
create or replace trigger all_actions
before insert or update or delete on students
declare
user_action system_events.action%type;
begin
if INSERTING then
user_action :='Insert';
elsif UPDATING then
user_action :='Update';
elsif DELETING then
user_action :='Delete';
else
raise_application_error (-20001, 'Yous should never get this error.');
end if;
insert into system_events(who,action,when) values(user,user_action,sysdate);
end;
So this trigger I created is working. However it doesn't check the Time. So I would like to add that feature of checking the Time and revolke the change if it's not in the right time
Thank you!!
It is not clear what do you mean by "revolke the change". I assume you want to stop the users from doing any DML operation except during work hours. If so, you could add another IF condition and raise an exception for times beyond 8am - 5pm.
CREATE OR replace TRIGGER all_actions
BEFORE INSERT OR UPDATE OR DELETE ON students
DECLARE
user_action system_events.action%TYPE;
BEGIN
IF inserting THEN
user_action := 'Insert';
ELSIF updating THEN
user_action := 'Update';
ELSIF deleting THEN
user_action := 'Delete';
ELSE
raise_application_error (-20001, 'You should never get this error.');
END IF;
IF to_number(to_char(SYSDATE, 'HH24')) NOT BETWEEN 8 AND 16 THEN
raise_application_error (-20001, 'You should not do '
||user_action
||' operation during this time.');
END IF;
INSERT INTO system_events
(who,
action,
when)
VALUES (USER,
user_action,
SYSDATE);
END;
/
Note: You may put this IF condition before checking the operation type as well if you want, without user_action
This trigger ends up raising an error regardless of the if statement values. I'm basically selecting from the same table the delete is occurring on and it's not liking it.
CREATE OR REPLACE TRIGGER delete_schedules
AFTER DELETE
ON SCHEDULES
FOR EACH ROW
DECLARE
lParentCond schedules.cond_code%type;
lParentActive schedules.active_flag%type;
lError exception;
BEGIN
if :OLD.thread is not null then
select cond_code, active_flag
into lParentCond, lParentActive
from schedules where schedule_seq = :old.thread;
if lParentCond = 'OK' and lParentActive in ('*', 'F') then
raise lError;
end if;
end if;
EXCEPTION
when lError then
raise;
WHEN OTHERS THEN RAISE;
END delete_schedules;
Any ideas of a workaround?
You're probably getting the dreaded 'MUTATING TABLE' error. Oracle doesn't allow us to fetch data from the table on which the trigger is defined in an AFTER trigger - but in this case you don't need to because the 'old' values are already available. Rewrite your trigger as:
CREATE OR REPLACE TRIGGER delete_schedules
AFTER DELETE
ON SCHEDULES
FOR EACH ROW
BEGIN
if :OLD.thread is not null AND
:OLD.COND_CODE = 'OK' and
:OLD.ACTIVE_FLAG in ('*', 'F')
then
RAISE_APPLICATION_ERROR(-20100, 'Invalid combination of COND_CODE and ACTIVE_FLAG');
end if;
END delete_schedules;
This assumes (based on the use of a singleton SELECT in the question) that there's only one row in SCHEDULES for the given THREAD value. If that's not the case there are other work-arounds, including using a COMPOUND TRIGGER.
Best of luck.
I have a Product table with 4 columns. 2 columns are price. If the ListPrice column is updated to below a specified amount (StandardCost * 1.2) then the update should fail and the old ListPrice should remain. I am attempting to use a SIGNAL SQLSTATE error to prevent the update from occurring if the criteria are met.
I've been combing Google and tried various variations in the syntax, but I keep hitting the following error while compiling my trigger - "PLS-00103 - Encountered the symbol 'SQLSTATE' when expecting one of the following: := , ( # %"
Any help is greatly appreciated.
CREATE OR REPLACE TRIGGER Product_Price_Check
BEFORE INSERT OR UPDATE OF ListPrice ON Product
FOR EACH ROW
DECLARE
min_price NUMBER(10, 2);
new_price NUMBER(10, 2);
BEGIN
min_price := (:OLD.StandardCost*1.2);
new_price := (:NEW.ListPrice);
IF (new_price < min_price) THEN
-- Rolls back an explicit or implicit transaction to the beginning of the transaction
dbms_output.put_line('the price can’t be below ' || TO_CHAR(min_price));
SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = 'Insert/update failed';
END IF;
END;
As mustaccio said, you're mixing MySQL syntax with an Oracle trigger. You want raise_application_error:
BEGIN
IF :NEW.ListPrice < (:OLD.StandardCost*1.2) THEN
raise_application_error(-20001,
'the price can’t be below ' || TO_CHAR(:OLD.StandardCost*1.2));
END IF;
END;
/
This won't roll back the transaction, just the update statement. The caller will receive the exception and decide how to handle it - whether to try again, roll back, or commit any other changes already made.
This assumes the old standard cost cannot be null. You might also want to specify a format model for the to_char().
Also don't rely on dbms_output for informing the caller about anything, as you won't know if the caller is looking at or doing anything with the buffer.
IF l_value = 'FALSE' THEN
RAISE_APPLICATION_ERROR(-20299, 'some error message');
END IF;
This is part of table trigger. It should return me a error number and message, but when alert pops out it returns only message number. No 'some error message'. Whats wrong
Maybe the name RAISE_APPLICATION_ERROR is misleading for you. It will not pop up something onto your GUI. That you program yourself depending on what client you are using. Put you can use RAISE_APPLICATION_ERROR to create your own SQL errors on which you act upon.
Example
-- a example table
create table mytest (col_a number, col_b char(20));
-- a example trigger
CREATE OR REPLACE TRIGGER mytest_before
BEFORE UPDATE
ON mytest
FOR EACH ROW
DECLARE
BEGIN
if :new.col_a < 0 then
RAISE_APPLICATION_ERROR(-20299, 'negative value not allowed for column A');
end if;
END;
insert into mytest values (1,'hallo');
set serveroutput on
DECLARE
negative_value EXCEPTION; -- declare exception
PRAGMA EXCEPTION_INIT (negative_value, -20299); -- assign error code to exception
BEGIN
update mytest set col_a = -1 where col_b = 'hallo';
EXCEPTION
WHEN negative_value THEN -- handle exception
-- do whatever you need to do to bring the error to the user
DBMS_OUTPUT.PUT_LINE(TO_CHAR(SQLERRM(-20299)));
END;
/
The above will bring you the output in SQL*Plus or SQL Developer of that sort.
table MYTEST created.
TRIGGER mytest_before compiled
1 rows inserted.
anonymous block completed
ORA-20299: negative value not allowed for column A
ORA-06512: at "DEMO.MYTEST_BEFORE", line 4
ORA-04088: error during execution of trigger 'DEMO.MYTEST_BEFORE
Instead of DBMS_OUTPUT.PUT_LINE you can do whatever you need to do to show the user whatever you want him to show.
The alert in your form has been raised by some trigger code on your form. Have a look at your ON-ERROR trigger - what code does it have?
You may need to augment it to show DBMS_ERROR_TEXT in the alert.