DBMS_OUTPUT.PUT_LINE not showing message to user - oracle

I am trying to create a trigger that would check for a null value in column namesdreservation_status from my table passenger and set it to a default value if it's null and show the user a message of it being set to default.
The trigger is created and works fine for setting the default but no message is shown to the user.
create or replace trigger mytrigger
before insert or update on passenger
for each row
when (new.reservation_status IS NULL)
begin
IF :new.reservation_status IS NULL THEN
:new.reservation_status := 'not reserved';
dbms_output.put_line('reservation status invalid, set to default');
end IF;
end mytrigger
/
The value gets changed to 'not reserved' if its null but the message 'reservation status invalid, set to default' isn't displayed. Help.

Trigger's don't do anything until they're actually triggered - in this case, on an INSERT.
clear screen
set serveroutput on
drop table passenger;
create table passenger (id integer, reservation_status varchar2(25));
create or replace trigger mytrigger
before insert or update on passenger
for each row
when (new.reservation_status IS NULL)
begin
IF :new.reservation_status IS NULL THEN
:new.reservation_status := 'not reserved';
dbms_output.put_line('reservation status invalid, set to default');
end IF;
end mytrigger;
/
insert into passenger values (1, null);
commit;
If I run this in SQLPlus, SQLcl, or SQL Developer -
And if we check the table, you can see our trigger, 'worked.'

Related

How to declare one variable for each row in trigger?

I have following trigger:
create or replace TRIGGER MY_TIGGER_NAME AFTER UPDATE ON MY_TABLE
REFERENCING OLD AS OLD NEW AS NEW FOR EACH ROW
WHEN ( NEW.STATUS = ANY (10,40,42,44,46,50,60) and OLD.STATUS != NEW.STATUS)
DECLARE
PRAGMA AUTONOMOUS_TRANSACTION;
BEGIN
IF :NEW.ALERT is NULL
THEN
dbms_alert.signal('print_update_event','update_message');
ELSE
dbms_alert.signal( :NEW.ALERT,'update_message');
END IF;
commit;
END;
I would like to change it because it send alert for each row. I would like to send only one alert if more than one row with ALERT column equal NULL was updated and I would like to send one alert for each row with ALERT column NOT equal NULL.
As I understand Oracle variables I can declare local variable in my trigger but this variable will be declared separately for each row so following change has no sense:
create or replace TRIGGER MY_TIGGER_NAME AFTER UPDATE ON MY_TABLE
REFERENCING OLD AS OLD NEW AS NEW FOR EACH ROW
WHEN ( NEW.STATUS = ANY (10,40,42,44,46,50,60) and OLD.STATUS != NEW.STATUS)
DECLARE
PRAGMA AUTONOMOUS_TRANSACTION;
flag NUMBER(1,0) :=0;
BEGIN
IF :NEW.ALERT is NULL and flag=0
THEN
dbms_alert.signal('print_update_event','update_message');
flag:=1;
ELSE
dbms_alert.signal( :NEW.ALERT,'update_message');
END IF;
commit;
END;
Package variable could be used instead local variable but I think that package variable is bad idea because two triggers can be executed in parallel. Maybe I am wrong.
I attach diagram of trigger which shows what I would like to achieve.
How to do it?

ORA-06502: PL/SQL: numeric or value error by ora_sql_txt(ora_name_list_t)

table:
create table EMPLOYEES_LOG
(
who VARCHAR2(300),
when DATE,
action VARCHAR2(2000)
)
trigger:
create or replace trigger aiud_employees_copy
after insert or update or delete
on employees_copy
declare
l_action employees_log.action%type;
l_sql_text ora_name_list_t;
begin
l_action := 'The statement that causes the change was:' || chr(10);
for i in 1..ora_sql_txt(l_sql_text) loop
l_action := l_action || l_sql_text(i);
end loop;
insert into employees_log(who, action, when)
values(user, l_action, sysdate);
end aiud_employees_copy;
execute:
update employees_copy set salary=salary*1.05 where department_id=20;
gives me the error:
ORA-06502: PL/SQL: numeric or value error at for i in 1..ora_sql_txt(l_sql_text) loop
thanks.
That function has an OUT parameter and returns a pls_integer number of elements. That document shows it being assigned to a variable:
l_n := ora_sql_txt(l_sql_text);
for i in 1..l_sql_text.count loop
So:
create or replace trigger aiud_employees_copy
after insert or update or delete
on employees_copy
declare
l_action employees_log.action%type;
l_sql_text ora_name_list_t;
l_n pls_integer;
begin
l_action := 'The statement that causes the change was:' || chr(10);
l_n := ora_sql_txt(l_sql_text);
for i in 1..l_sql_text.count loop
l_action := l_action || l_sql_text(i);
end loop;
insert into employees_log(who, action, when)
values(user, l_action, sysdate);
end aiud_employees_copy;
/
... although referring to it directly should work.
But ora_sql_txt() is for system event triggers; for a DML trigger it will return null (apart from some versions of 9i, which seem to have been unintentional; see bug 4230721). The seciotn of the documentation the function is described in is "Triggers for Publishing Events", and it makes it clear that they only apply to certain database and client events.
By invoking system-defined event attribute functions in Table 9-4, a trigger can retrieve certain attributes of the triggering event. Not all triggers can invoke all event attribute functions—for details, see "Event Attribute Functions for Database Event Triggers" and "Event Attribute Functions for Client Event Triggers".
So ora_sql_txt(l_sql_text) will be null, which is the value error you're getting. If you assign it to a variable first you'll still get an error. You can nvl() it to zero, but since it will always be null (and hence zero rows once you do that) it's a bit pointless.

Cursors in oracle PL/SQL

I am trying to do a trigger that updates a status of a grade on update of the grade or a insert of a new one.
Thats my table
create table Enrollment (
Student_ID char(9) not null,
Course_ID char(5) not null,
Registered_Date date,
Grade NUMBER,
Status varchar(4),
constraint pkEnrollment primary key (Student_ID, Course_ID));
That's my code so far and i don't know what's the problem
create or replace TRIGGER PASS_FAIL
AFTER INSERT OR UPDATE OF GRADE ON ENROLLMENT
DECLARE
CURSOR change_grade IS
select GRADE, STATUS from ENROLLMENT FOR UPDATE;
newgrade ENROLLMENT.GRADE%type;
newstatus ENROLLMENT.STATUS%type;
BEGIN
OPEN change_grade;
LOOP
FETCH change_grade into newgrade,newstatus;
IF newgrade>=60 THEN UPDATE ENROLLMENT SET STATUS = 'Pass' WHERE CURRENT OF change_grade;
ELSE UPDATE ENROLLMENT SET STATUS = 'Fail' WHERE CURRENT OF change_grade;
END IF;
EXIT WHEN change_grade%NOTFOUND;
END LOOP;
CLOSE change_grade;
END;
When i tried to change the grade i get
UPDATE "FELIX"."ENROLLMENT" SET GRADE = '10' WHERE ROWID = 'AAAGETAABAAALKJAAE' AND ORA_ROWSCN = '3332070'
ORA-04098: trigger 'FELIX.ELIGIBLE_ENROLLMENT' is invalid and failed re-validation
One error saving changes to table "FELIX"."ENROLLMENT":
Row 5: ORA-04098: trigger 'FELIX.ELIGIBLE_ENROLLMENT' is invalid and failed re-validation
Thanks in advance for the help
Your code seems excessively complicated unless the point is to learn about cursors.
CREATE OR REPLACE TRIGGER PASS_FAIL
Before INSERT OR UPDATE
ON enrollment
REFERENCING NEW AS New OLD AS Old
FOR EACH ROW
DECLARE
/******************************************************************************
NAME: PASS_FAIL
PURPOSE:
USED BY:
REVISIONS:
Ver Date Author Description
--------- ---------- --------------- ------------------------------------
1.0 1. Created this trigger.
NOTES:
******************************************************************************/
BEGIN
if :new.grade > 60 THEN
:new.status := 'PASS';
ELSE
:new.status := 'FAIL';
END IF;
EXCEPTION
WHEN OTHERS
THEN
-- Log the error and then re-raise
RAISE;
END PASS_FAIL;

Oracle : How to have only one row active in a table?

I have an Oracle table with a field Named Active.
This field has a unique constraint, so only one row will be marked as Active.
Is there any way in the database layer to keep only one row active when adding a new row or updating old ones ?
Example
Current State of Table
ID Active
----------------
1 yes
A new active row is added :
New State of the table
ID Active
----------------
1 No
2 Yes
The row 1 is updated with Active = Yes
ID Active
----------------
1 Yes
2 No
Of course I can not update the table using a trigger when a new row is beign inserted.
Does anyone have an idea on how to do that please ?
You need to call this procedure with valid values as input parameter
CREATE OR REPLACE PROCEDURE t416493.set_tab
(
p_id IN tab.id%TYPE
,p_active_flag IN tab.active%TYPE
,p_dml_type IN VARCHAR2
)
IS
CURSOR check_flag_exists
IS
SELECT id
FROM tab
WHERE active = p_active_flag;
v_id tab.id%TYPE;
v_active_flag VARCHAR2(3);
BEGIN
OPEN check_flag_exists;
FETCH check_flag_exists INTO v_id;
IF check_flag_exists%FOUND THEN
IF p_active_flag ='Yes' THEN
v_active_flag :='No';
ELSE
v_active_flag :='Yes';
END IF;
UPDATE tab
SET active = v_active_flag
WHERE id =v_id;
END IF;
CLOSE check_flag_exists;
IF p_dml_type ='INSERT' THEN
INSERT INTO tab
(id
,active
)
VALUES
(p_id
,p_active_flag
);
ELSIF p_dml_type ='UPDATE' THEN
UPDATE tab
SET active =p_active_flag
WHERE id =v_id;
END IF;
END set_tab;
You need to call your proc like this as shown below:
begin
set_tab
(
p_id =>2
,p_active_flag =>'Yes'
,p_dml_type =>'INSERT'
);
end;
/

Oracle After Update Trigger error

I want to keep track of changes to one table in another table. What I need is an after update trigger which writes the name of changed column (if multiple columns are changed then there will be multiple inserts to the CHANGES table),the column's old and new values. How do I do that. I tried this but got an error after updating the table.So I'm giving you just the body.
IF :NEW.STAJYEAR!=:OLD.STAJYEAR THEN
INSERT INTO X_STAJ (USERID,EDITDATE,CHANGEDCOLUMN,OLDVALUE,NEWVALUE)
VALUES (:NEW.USERID,SYSDATE,'STAJYEAR',:OLD.STAJYEAR,:NEW.STAJYEAR);
END IF;
the error code is :ORA-04098: trigger 'SYS.TR__TRACK_CHANGES' is invalid and failed re-validation
CREATE OR REPLACE TRIGGER STAJCHANGER.TR_TRACK_CHANGES
AFTER UPDATE
OF STAJYEAR
,STAJMONTH
,STAJDAY
ON STAJCHANGER.STAJ
REFERENCING NEW AS New OLD AS Old
FOR EACH ROW
DECLARE
OLDVALUE NUMBER;
NEWVALUE NUMBER;
COLUMNID NUMBER;
BEGIN
IF :NEW.STAJYEAR!=:OLD.STAJYEAR THEN
INSERT INTO X_STAJ (USERID,EDITDATE,CHANGEDCOLUMN,OLDVALUE,NEWVALUE)
VALUES (:NEW.USERID,SYSDATE,'STAJYEAR',:OLD.STAJYEAR,:NEW.STAJYEAR);
END IF;
IF :NEW.STAJMONTH!=:OLD.STAJMONTH THEN
INSERT INTO X_STAJ (USERID,EDITDATE,CHANGEDCOLUMN,OLDVALUE,NEWVALUE)
VALUES (:NEW.USERID,SYSDATE,'STAJMONTH',:OLD.STAJMONTH,:NEW.STAJMONTH);
END IF;
IF :NEW.STAJDAY!=:OLD.STAJDAY THEN
INSERT INTO X_STAJ (USERID,EDITDATE,CHANGEDCOLUMN,OLDVALUE,NEWVALUE)
VALUES (:NEW.USERID,SYSDATE,'STAJDAY',:OLD.STAJDAY,:NEW.STAJDAY);
END IF;
END TR_TRACK_CHANGES;
/
The error appears to indicates that the trigger owner is SYS, but the creation statement you show explicitly gives the owner as STAJCHANGER.
This makes me wonder, did you accidentally create an (invalid) version of the trigger in SYS at some point, and forget to drop it?
This SQL Plus command will show the error:
SHOW ERROR TRIGGER STAJCHANGER.TR_TRACK_CHANGES

Resources