Why does my SQL trigger statement not appear in DBMS_OUTPUT? - sql

I'm trying to get my head around triggers, but I'm getting errors
Error(2,4): PL/SQL: SQL Statement ignored
Error(2,8): PL/SQL: ORA-00922: missing or invalid option
when creating the following trigger:
CREATE TRIGGER TableTrigger
AFTER UPDATE ON TestTable
FOR EACH ROW
BEGIN
set serveroutput on format wrapped;
DBMS_OUTPUT.put_line('TABLE UPDATED!');
END;
Which works on the following table:
CREATE TABLE TestTable
(
test1 INT,
test2 INT,
test3 INT,
PRIMARY KEY (test1)
);
I'm not sure what to do, does anyone have any suggestions?

Using DBMS_OUTPUT in triggers is not best practice. If you want to see that something was done create a logging table or an audit history table or set auditing of update on for that table.
DBMS_OUTPUT is useful when you are running a PL/SQL procedure or package from SQLPlus or other IDE.
Different versions of SQL may or may not show you the output of the buffer from a trigger.

Related

Oracle PL/SQL - BEFORE INSERT 'table does not exist' error?

I'm taking my first steps in Pl/SQL and am struggling with triggers. I've tried creating the trigger below but am receiving this error:
Error at line 2: PL/SQL: SQL Statement ignored
PL/SQL: ORA-00942: table or view does not exist
To clarify: I have checked the name of the table over and over, and it does exist. It is also in the same schema as the trigger I'm trying to create. The 'customer_seq.NEXTVAL' refers to a sequence created previously that runs without errors.
The code is as follows:
CREATE TRIGGER new_customer
BEFORE INSERT ON customer
FOR EACH ROW
BEGIN
INSERT INTO customer_id VALUES ('c-', customer_seq.NEXTVAL);
END;
Thanks in advance for any help.
You probably intend something like this:
CREATE TRIGGER new_customer
BEFORE INSERT ON customer
FOR EACH ROW
BEGIN
SELECT customer_seq.NEXTVAL INTO :NEW.customer_id
FROM dual;
END;
It is unclear what the purpose of 'C_' is. If it is part of the customer id, I would advise you to stick to numbers.
Also note that more recent versions of Oracle support generated always as identity -- which is much preferred over defining a sequence and trigger.

Oracle Apex: Success With compilation error

I'm trying to create a procedure named "Greetings" in the oracle apex. The Procedure Greetings runs with some error throwing up called "Success with compilation error". Is there anything wrong with my below code.
Code:
create table tb_Animals (
txt_Name varchar(20) Primary Key,
int_Weight number
);
insert into tb_Animals values ('Dog',30);
insert into tb_Animals values ('Cat',15);
CREATE OR REPLACE PROCEDURE greetings
AS
BEGIN
select * from tb_Animals;
END;
In PL/SQL, you have to insert those values into something, usually a variable, However, if you're selecting the whole table contents, then it has to be something else; one option might be a refcursor. For example:
SQL> CREATE OR REPLACE PROCEDURE greetings
2 AS
3 rc sys_refcursor;
4 BEGIN
5 open rc for
6 select * from tb_Animals;
7 END;
8 /
Procedure created.
SQL>
It is now correct as far as compilation is concerned, but - actual "solution" depends on what you really want to do.
Two problems I see here:
The code you provided is a SQL script that will create the procedure, not run the procedure. The error is telling you that the procedure has been created, but that it has an error. You can see the precise error by entering "SHOW ERRORS" at the sqlplus prompt after the create command completes.
The problem with the procedure itself is that you have to do something with the data you've selected. It needs to be processed into variables, or used in a for/next loop for some purpose. Simply selecting data into nothing won't work - PL/SQL is a programming language, not a scripting language. See here for a beginner's guide: https://oracle-base.com/articles/misc/introduction-to-plsql. I can't offer any more specific guidance than that since you've not provided any info on what your procedure is actually trying to do.
If you just want your script to return the data you just inserted into the table as a confirmation, just run the select statement without the procedural stuff, like this (and don't forget to commit your changes!):
create table tb_Animals (
txt_Name varchar(20) Primary Key,
int_Weight number
);
insert into tb_Animals values ('Dog',30);
insert into tb_Animals values ('Cat',15);
commit;
select * from tb_Animals;

insert statement inside stored procedure failing

I have written a oracle stored procedure and creating an error log table if that doesn't exist.
SELECT COUNT(*)
INTO v_count
FROM all_tables
WHERE TABLE_NAME = 'ERROR_LOG';
IF v_count =0 THEN
cr_table := 'CREATE TABLE ERROR_LOG ( ERROR_LOG_ID NUMBER GENERATED BY DEFAULT ON NULL AS IDENTITY, IDENTIFIER VARCHAR2(100), ERROR_MESSAGE VARCHAR2(1000),created_by varchar2(100 ), created_date TIMESTAMP DEFAULT systimestamp )';
execute immediate cr_table;
then issuing an insert statement below in the code as
INSERT
INTO error_log
(
identifier,
error_message,
created_by
)
VALUES
(
v_identifier,
'Success',
v_user
);
But the SP is throwing compilation error with
PL/SQL: ORA-00942: table or view does not exist
If I create the table manually, offline, and compile then it works.
any help?
if you use execute immediate to create a table, it exists in the PL/SQL context, not in SQL context, you have to execute the INSERT by using execute immedation too.
Or you have to make the insert inside an other BEGIN.. END block.
Before using the stored procedure, please create a view or table where you are going to insert the values using the SP. So it will avoid the compiler error in the run time.
This is too long for a comment.
The table doesn't exist when the code is compiled. Hence, you are getting a compile-time error. At compilation time, Oracle doesn't know that the table will exist when executed.
One solution is to use dynamic SQL for the insert as well.
A better solution is to set up the database with the appropriate tables before the code can ever be executed. Creating permanent tables dynamically in conditional code is usually a sign of a poorly designed application.

PL/SQL Trigger Issues

I am trying to write a trigger to populate a table containing information on an employee's updated salary. I'm having a problem that I can't quite wrap my head around at the moment.
Here is the table to be populated:
drop table SalUpdates cascade constraints;
create table SalUpdates(
SalSSN char(9),
newSalary decimal(10,2),
oldSalary decimal(10,2)
);
This is my trigger:
create or replace trigger t1
after update of salary on employee
for each row
begin
insert into SalUpdates values (:old.Ssn, :new.salary, :old.salary);
end;
The trigger compiles with no issues, but when I try to run this update, Oracle tells me my trigger is invalid. What could be causing this?
update employee
set salary=4000
where ssn='123456789';
You've shown the code in chunks. but it seems you're running what you've shown together as a script, initially without the update:
drop table SalUpdates cascade constraints;
create table SalUpdates(
SalSSN char(9),
newSalary decimal(10,2),
oldSalary decimal(10,2)
);
create or replace trigger t1
after update of salary on employee
for each row
begin
insert into SalUpdates values (:old.Ssn, :new.salary, :old.salary);
end;
When run as a script in SQL Developer the script output window shows:
drop table SalUpdates cascade constraints
Error report -
ORA-00942: table or view does not exist
00942. 00000 - "table or view does not exist"
*Cause:
*Action:
Table SALUPDATES created.
Trigger T1 compiled
If you then add the update statement to the script:
drop table SalUpdates cascade constraints;
create table SalUpdates(
SalSSN char(9),
newSalary decimal(10,2),
oldSalary decimal(10,2)
);
create or replace trigger t1
after update of salary on employee
for each row
begin
insert into SalUpdates values (:old.Ssn, :new.salary, :old.salary);
end;
update employee
set salary=4000
where ssn='123456789';
you get:
Table SALUPDATES dropped.
Table SALUPDATES created.
Trigger T1 compiled
Errors: check compiler log
If you then try to run the update on it's own (as a statement instead of a script; or by selecting that test and running as a script) you do indeed get:
SQL Error: ORA-04098: trigger 'MYSCHEMA.T1' is invalid and failed re-validation
04098. 00000 - "trigger '%s.%s' is invalid and failed re-validation"
*Cause: A trigger was attempted to be retrieved for execution and was
found to be invalid. This also means that compilation/authorization
failed for the trigger.
*Action: Options are to resolve the compilation/authorization errors,
disable the trigger, or drop the trigger.
If you query the user_errors view, or run show errors, you'll see:
PLS-00103: Encountered the symbol "UPDATE"
The problem is that you aren't completing the create trigger statement properly. The update is being seen as part of the same PL/SQL block; an invalid part, but still included.
When you have a PL/SQL block you have to terminate it with a slash, as it explains in the SQL*Plus documentation (which mostly applies to SQL Developer too):
SQL*Plus treats PL/SQL subprograms in the same manner as SQL commands, except that a semicolon (;) or a blank line does not terminate and execute a block. Terminate PL/SQL subprograms by entering a period (.) by itself on a new line. You can also terminate and execute a PL/SQL subprogram by entering a slash (/) by itself on a new line.
SQL Developer doesn't complain if the last block in a script doesn't have a terminating slash though, so your original script (without the update) works; in SQL*Plus it would sit at a prompt. It kind of infers that it should be there - trying to be helpful. When you add the update statement it is no longer the end of the script so that doesn't apply.
If you add a slash to your script between the PL/SQL code and the following SQL statement it all works:
drop table SalUpdates cascade constraints;
create table SalUpdates(
SalSSN char(9),
newSalary decimal(10,2),
oldSalary decimal(10,2)
);
create or replace trigger t1
after update of salary on employee
for each row
begin
insert into SalUpdates values (:old.Ssn, :new.salary, :old.salary);
end;
/
update employee
set salary=4000
where ssn='123456789';
and you now see:
Table SALUPDATES dropped.
Table SALUPDATES created.
Trigger T1 compiled
1 row updated.

SQL trigger error - invalid trigger

I'm using pl\sql developer and I have a report table with a number(38) ID column.
I want to keep track of all updates for this table so I created another table like this:
CREATE TABLE reportUpdate (report_id number(38), updatedate number(32));
And I created a trigger:
CREATE or REPLACE TRIGGER BeforeUpdateReport
BEFORE
UPDATE ON REPORT
FOR EACH ROW
Begin
INSERT INTO reportUpdate
Values(old.ID,sysdate);
END;
And when I run it, I get an error, saying: trigger 'SYSTEM.BEFOREUPDATEREPORT' is invalidand failed re-validation.
Can someone please help
You can use show errors after you see compiled with warnings, or query the user_errors view to see what is wrong later.
One obvious thing is that you haven't prefixed the old reference with a colon:
CREATE or REPLACE TRIGGER BeforeUpdateReport
BEFORE
UPDATE ON REPORT
FOR EACH ROW
Begin
INSERT INTO reportUpdate
Values(:old.ID,sysdate);
END;
/
It's also better to specify the target table fields in the insert statement:
INSERT INTO reportUpdate (report_id, updatedate)
Values(:old.ID,sysdate);
But you have update_date defined in your table creation script as number(32), which doesn't make sense. As #realspirituals pointed out, it should be:
CREATE TABLE reportUpdate (report_id number, updatedate date);