I am trying to create a trigger to check the month before inserting to the database. the followingg code was triedbut showing a complationng error as Warning: Trigger created with compilation errors.
this is the code
CREATE OR REPLACE TRIGGER tr_july
BEFORE INSERT
ON TBL_EVENT
BEGIN
SELECT EXTRACT(month FROM EVN_DATE) FROM TBL_EVENT;
IF EXTRACT (month from EVN_DATE) == 7 THEN
RAISE_APPLICATION_ERROR(-20110, 'NOT ALLOWED TO INSERT RECORDS DURING JULY');
END IF;
END;
/
I think you are looking for something like this:
CREATE OR REPLACE TRIGGER tr_july
BEFORE INSERT ON TBL_EVENT
BEGIN
IF EXTRACT (month from :new.EVN_DATE) = 7 THEN
RAISE_APPLICATION_ERROR(-20110, 'NOT ALLOWED TO INSERT RECORDS DURING JULY');
END IF;
END; /
Study the documentation, a section "Accessing Column Values in Row Triggers"
https://docs.oracle.com/cd/B19306_01/appdev.102/b14251/adfns_triggers.htm
to learn how to access columns of the current row within the trigger body.
In short: You need to use "correlation names" named NEW and OLD
Tip: run SET DEFINE OFF; before compiling the trigger to avoid bind variable substitution (variables prepended by a colon :).
Use it as:
CREATE OR REPLACE TRIGGER tr_july
BEFORE INSERT
ON TBL_EVENT
Declare
E_date date;
BEGIN
SELECT EVN_DATE into E_date FROM TBL_EVENT;
IF EXTRACT (month from E_date) = 7 THEN
RAISE_APPLICATION_ERROR(-20110, 'NOT ALLOWED TO INSERT RECORDS DURING JULY');
END IF;
END;
Note: Oracle if clause require = only once
There are multiple isues with this code.
First it is a before insert trigger, so the value you want to check is not yet in the table. You can't find it with a select.
Triggers are pl/sql code. Any value you select within a pl/sql procedure you have to 'select aaa INTO bbb from xxx; and bbb must be declared before your BEGIN.
In Oracle the equal comparison operator is a single = (not ==).
Within a trigger you have the special qualifiers :new and :old to reference the column values you are working on.
In update triggers only the :new qualifier is usable.
CREATE OR REPLACE TRIGGER tr_july
BEFORE INSERT
ON TBL_EVENT
BEGIN
IF EXTRACT (month from :new.EVN_DATE) = 7 THEN
RAISE_APPLICATION_ERROR(-20110, 'NOT ALLOWED TO INSERT RECORDS DURING JULY');
END IF;
END;
Related
Im trying to create a trigger when updating table 'test' to make sure a value in a column is not greater than another one from a different table. But I get this error on Oracle Apex: ORA-24344: success with compilation error
'test' is a table and 'chestionar' is a second one, so I want to launch that error when I insert a value in 'punctaj' which is greater than the 'punctaj_max'. And the id of the both tables must be the same . What should I modify?
here is my code:
CREATE OR REPLACE trigger trg_a
BEFORE UPDATE on test
begin
if test.punctaj > chestionar.punctaj_max and test.id=chestionar.id then
raise_application_error(234,'error, the value is grater than maximum of that id');
end if;
end;
I think the logic you want is:
create or replace trigger trg_a
before update on test
for each row
declare
p_punctaj_max chestionar.punctaj_max%type;
begin
select punctaj_max into p_punctaj_max from chestionar c where c.id = :new.id;
if :new.punctaj > p_punctaj_max then
raise_application_error(234, 'error, the value is grater than maximum of that id');
end if;
end;
/
The idea is to recover the value of punctaj_max in table chestionar for the id of the row that is being updated in test (note that this implicitely assumes that there cannot be multiple matching rows in chestionar). We can then compare that to the value being updated, and raise the error if needed.
You have three (I think) issue in your code:
You should apply trigger at time of insert also.
you need to query the table chestionar and then compare the value.
the error number in raise_application_error should be negative and between -20999 and -20000.
So, I would rewrite your code as follows:
create or replace trigger trg_a
before update or insert on test
for each row
declare
lv_cnt number := 0;
begin
select count(1) into lv_cnt
from chestionar c
where c.id = :new.id
and :new.punctaj > c.punctaj_max;
if lv_cnt > 0 then
raise_application_error(-20234, 'error, the value is grater than maximum of that id');
end if;
end;
/
I am trying to use v('APP_USER') as default value for a column. I get null when I use it in select like
select v('APP_USER') from dual;
But when I use it as default in column, like below, I am getting error.
create table test_table (col_1 varchar2(50) default NVL(v('APP_USER'), SYS_CONTEXT('USERENV','OS_USER')));
Error
create table test_table (col_1 varchar2(50) default NVL(v('APP_USER'), SYS_CONTEXT('USERENV','OS_USER')))
Error report -
ORA-04044: procedure, function, package, or type is not allowed here
04044. 00000 - "procedure, function, package, or type is not allowed here"
*Cause: A procedure, function, or package was specified in an
inappropriate place in a statement.
*Action: Make sure the name is correct or remove it.
Can anyone explain this or have a turnaround for this ??
There are other options than V('APP_USER'). Since Apex 5, the APP_USER is stored in the sys_context and that is a lot more performant than the V() function. It is available as SYS_CONTEXT('APEX$SESSION','APP_USER').
It also works as a default value for tables:
create table test_table
(col_1 VARCHAR2(100) DEFAULT SYS_CONTEXT('APEX$SESSION','APP_USER'));
Table TEST_TABLE created.
That being said, the best practice for audit columns is a trigger that populates the the 4 audit columns (as #Littlefoot suggested). Have a look at quicksql (under SQL Workshop > Utilities or on livesql.oracle.com). You can have it generate the triggers for you if you set "include Audit columns" and "Apex Enabled". An example of such a generated trigger is:
create or replace trigger employees_biu
before insert or update
on employees
for each row
begin
if inserting then
:new.created := sysdate;
:new.created_by := nvl(sys_context('APEX$SESSION','APP_USER'),user);
end if;
:new.updated := sysdate;
:new.updated_by := nvl(sys_context('APEX$SESSION','APP_USER'),user);
end employees_biu;
/
One option is to use a database trigger, e.g.
CREATE OR REPLACE TRIGGER trg_biu_test
BEFORE INSERT OR UPDATE ON test
FOR EACH ROW
BEGIN
:new.col1 := v ('APP_USER');
END;
/
The entire question I'm trying to answer is:
Utilize the travel anywhere database to create a database trigger "hotel_kids_rule" to enforce a business rule. when inserting a hotel_reservation, if the num_kids value is more than zero, then assign the bed_type DQ to the reservation. save the trigger source as a script file.
For example, the trigger will change the bed_type for the following insert statement.
insert into hotel_reservation (reserve_no,reserve_date,arrival_date,dep_date,num_adults,num_kids,customer_id,hotel_id,bed_type,rooms)
values(hotel_reserve_sequence.nextval,sysdate,sysdate+5,sysdate+7,1,2,101,19,'DT',1);
For example, the trigger will not change the bed_type for the following insert statement.
insert into hotel_reservation (reserve_no,reserve_date,arrival_date,dep_date,num_adults,num_kids,customer_id,hotel_id,bed_type,rooms)
values(hotel_reserve_sequence.nextval,sysdate,sysdate+5,sysdate+7,2,0,102,20,'DT',1);
This is what I have so far:
create or replace trigger hotel_kids_rule
after insert or update on hotel_reservation
for each row
when (num_kids > 0)
declare
new_bed_type varchar2(20);
new_bed_type='DQ'
begin
new.bed_type=new_bed_type;
end;
Any help would be appreciated! Thanks!
I think you want a before trigger, so you can set the new value before it is written. Also, the way you access new is not ok: within the trigger code, you need :new.bed_type; in the when condition, you want new.num_kids.
This should work:
create or replace trigger hotel_kids_rule
before insert or update on hotel_reservation
for each row
when (new.num_kids > 0)
begin
:new.bed_type := 'DQ';
end;
/
Here is a small demo.
The assignment of your variable needs to be inside the actual code block. And the assignment operator is := in PL/SQL, not =. If you want the trigger to change anything you also need to create it as a BEFORE trigger:
create or replace trigger hotel_kids_rule
before insert or update on hotel_reservation
for each row
when (new.num_kids > 0)
declare
new_bed_type varchar2(20);
begin
new_bed_type := 'DQ';
:new.bed_type := new_bed_type;
end;
Note that the new record in the when condition is used without the colon : while inside the code block it needs to be referenced with the colon.
Alternatively initialize the variable when declaring it:
declare
new_bed_type varchar2(20) := 'DQ';
begin
:new.bed_type := new_bed_type;
end;
Or even simpler without any intermediate variable.
begin
:new.bed_type := 'DQ';
end;
I created table to store informations about time of any update, insert or delete data in one of tables.
CREATE TABLE dept_changes ( data DATE, action VARCHAR2(16) );
Now I want to create trigger inputing the data to table:
CREATE OR REPLACE TRIGGER dept_changes_trig AFTER UPDATE OR INSERT OR DELETE ON departments
DECLARE
action VARCHAR2(16);
BEGIN
IF UPDATING THEN
action:='upd';
END IF;
IF INSERTING THEN
action:='ins';
END IF;
IF DELETING THEN
action:='del';
END IF;
INSERT INTO DEPT_CHANGES (SYSDATE, action);
END;
I got 2 errors in line 12 (END IF of DELETING condition statement).
Error(12,5): PL/SQL: SQL Statement ignored
Error(12,46): PL/SQL: ORA-00926: missing VALUES keyword
I don't understand, what VALUES am I missing? What the trigger needs to work properly?
Use the values keyword
INSERT INTO DEPT_CHANGES VALUES (SYSDATE, action);
Insert Examples
Oracle 12c.
I currently have a table to hold patient visits containing a physician id, patient id, and data/time of visit.
I would like to create a constraint that, upon data entry, checks whether a specific physician has 5 appointments in that given day. If the physician does have 5 appointments, no additional appointment can be added.
Is there any way to do this other than using a stored procedure for entry?
If I were to use a stored procedure (as opposed to a trigger due issues declaring a variable) I receive the following error: Error(4,8): PLS-00103: Encountered the symbol "UPDATE" when expecting one of the following: := . ( # % ; not null range default character
I am unsure if this is because I can't use a BEFORE UPDATE on a procedure. Any thoughts?
CREATE OR REPLACE PROCEDURE doc_apt_limit_5
IS
v_visit_count
BEFORE UPDATE OR INSERT ON aa_patient_visit
FOR EACH ROW
BEGIN
SELECT (COUNT(*)) INTO v_visit_count
FROM aa_patient_visit
WHERE physid = :NEW.physid
GROUP BY physid, visittime;
IF v_visit_count > 4 THEN
RAISE_APPLICATION_ERROR(-20001, 'physician is fully booked on this date');
END IF;
END;
Go with trigger. Probably the best solution in this scenario.
CREATE OR REPLACE TRIGGER doc_apt_limit_5 BEFORE
UPDATE OR
INSERT ON aa_patient_visit FOR EACH ROW
DECLARE v_visit_count PLS_INTEGER;
BEGIN
SELECT COUNT(*)
INTO v_visit_count
FROM aa_patient_visit
WHERE physid = :NEW.physid
GROUP BY physid,
visittime;
IF v_visit_count > 4 THEN
RAISE_APPLICATION_ERROR(-20001, 'physician is fully booked on this date');
END IF;
END;