Handling a "too many values" exception in PLSQL - sql

I need to handle the "too many values" exception in a PLSQL program.
The table is:
Table structure of emptest
But I am not able to handle the exception and the program always shows a pre-defined error.
Anybody has any ideas?
I tried like this:
enter image description here
Not getting the user defined message.

The issue is that, in your table you have only four columns.
ENO
ENAME
ESAL
DEPTNAME
but you are tying to insert five column values.
insert into emptest values(v_eno, v_ename, v_esal, v_deptname, v_deptno);
Why are you inserting v_deptno when it is not present in the table?
Either alter your table and add one more column or update the code to insert four column value only.

What you are trying will not work. The pl/sql block will not compile because the sql statement is invalid - it has too many values.
I think you want to trap the error and show your own error message. But, you need to use EXECUTE IMMEDIATE in order to allow invalid sql in pl/sql.
To trap a specific oracle error with a custom message, use EXCEPTION_INIT
Here is an example:
create table testa (col1 NUMBER);
set serveroutput on size 999999
clear screen
DECLARE
-- unnamed system exception
too_many_values EXCEPTION;
PRAGMA EXCEPTION_INIT (too_many_values, -00913);
c_too_many_values VARCHAR2(512) := 'Dude, too many values !';
BEGIN
BEGIN
EXECUTE IMMEDIATE 'INSERT INTO testa VALUES (1,2)';
EXCEPTION WHEN too_many_values THEN
dbms_output.put_line(c_too_many_values);
END;
END;
/
Dude, too many values !
PL/SQL procedure successfully completed.

In you table you only have four columns, but you try to insert five column so error is generated error.
v_deptno is not your table
change your query as per following
Insert Into emptest values(v_eno, v_ename, v_esal, v_deptname);
or add one more column to your table
ALTER TABLE emptest ADD DEPTNO Number(4);

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.

How to successfully reference another table before insert with a trigger

I'm trying to create a trigger to validate if a new entry in the table registraties (registrations) contains a valid MNR (employee number) but I'm getting stuck on the part where I'm referencing the table medewerkers (employees).
Could someone help me out?
CREATE OR REPLACE TRIGGER t_MNRcontrole
BEFORE INSERT OR UPDATE
ON registraties
DECLARE
MNR_medewerkers number (SELECT MNR FROM MEDEWERKERS);
FOR EACH ROW
BEGIN
IF :new.MNR <> MNR_medewerkers
THEN raise_application_error(-20111, 'Medewerker niet herkend!');
END IF;
END;
Error message received is
ORA-24344: success with compilation error
The PL/SQL assignment operator is :=, or select x into y from z to populate from a SQL query.
FOR EACH ROW is part of the trigger spec, not the PL/SQL code.
If :new.mnr is not present in the parent table, you will get a no_data_found exception, not a mismatched variable.
It's good practice for error messages to include details of what failed.
In programming, we use indentation to indicate code structure.
A fixed version would be something like:
create or replace trigger trg_mnrcontrole
before insert or update on registraties
for each row
declare
mnr_medewerkers medewerkers.mnr%type;
begin
select mw.mnr into mnr_medewerkers
from medewerkers mw
where mw.mnr = :new.mnr;
exception
when no_data_found then
raise_application_error(-20111, 'Medewerker '||:new.mnr||' niet herkend!');
end;
However, we can implement this kind of check better using a foreign key constraint, for example:
alter table registraties add constraint registraties_mw_fk
foreign key (mnr) references medewerkers.mnr;
MNR_medewerkers number (SELECT MNR FROM MEDEWERKERS);
will always fail because its not a NUMBER, unless your table happens to only have one single entry and even then I am not sure PLSQL will allow it to pass.
The more standard case for this would be to first declare the number, then in the codeblock you do a SELECT INTO along with a WHERE clause where you make sure to only pick one specific row from the table. Then you can compare that number with the new one.
If however you are not trying to compare to one specific row, but are instead checking if the entry exists in that table.
BEGIN
SELECT 1
INTO m_variable
FROM table
WHERE MNR = :new.MNR;
EXCEPTION
WHEN TOO_MANY_ROWS THEN
m_variable = 1;
WHEN OTHERS THEN
m_variable = 0;
END;
Declare the m_variable beforehand, and then check if its 0 then report the error.
The too_many_rows is in case there is more than one row in the table with this MNR, and the OTHERS is there for the NO_DATA_FOUND, but I use OTHERS to handle everything else that could happen but probably wont.
Btw this is a code block to be included within the main code block, so between your BEGIN and IF, then just change the IF to check if the variable is 0.

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;

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.

PLS-00103: Encountered the symbol "end-of-file" when expecting one of the following: ;

I am running the following script -
BEGIN
select department_name
from egpl_department
where department_id in (select department_id
from egpl_casemgmt_activity);
END ;
And got the Error -
PLS-00103: Encountered the symbol "end-of-file" when
expecting one of the following:
;
In a PL/SQL block select statement should have an into clause:
DECLARE
v_department egpl_department.department_name%type;
BEGIN
select department_name
into v_department
from egpl_department
where department_id in (select department_id from egpl_casemgmt_activity);
-- Do something useful with v_department
END;
PLS-00103 always means the compiler has hurled because we have made a syntax error. It would be really neat if the message text said: You have made a syntax error, please check your code but alas it doesn't.
Anyway, in this case the error is that in PL/SQL select statements must populate a variable. This is different from the behaviour of say T-SQL. So you need to define a variable which matches the projection of your query and select INTO that variable.
Oracle's documentation is comprehensive and online. You can find the section on integrating SQL queries into PL/SQL here. I urge you to read it, to forestall your next question. Because once you have fixed the simple syntax bloomer you're going to hit TOO_MANY_ROWS (assuming you have more than one department).
In PL/SQL you cannot just select some data. Where is the result supposed to go?
Your options are:
Remove BEGIN and END and run the SELECT with SQL*plus or some other tool that can run a SQL statement and present the result somewhere.
Use SELECT department_name INTO dep_name to put the result into a PL/SQL variable (only works if your SELECT returns a single row)
Use SELECT department_name BULK COLLECT INTO dep_name_table to put the result into a PL/SQL table (works for several rows)
Or maybe you can describe what you're trying to achieve and in what environment you want to run the SQL or PL/SQL code.
To avoid the too_many_rows problem, you could use a cursor, something like this (I haven't tested this, but along these lines )
DECLARE
v_department egpl_department.department_name%type;
cursor c_dept IS
select department_name
into v_department
from egpl_department
where department_id in (select department_id from egpl_casemgmt_activity)
order by department_name;
BEGIN
OPEN c_dept;
FETCH c_dept INTO v_department;
CLOSE c_dept;
-- do something with v_department
END;
This will put the first value it finds in the table into v_department. Use the ORDER BY clause to make sure the row returned would be the one you required, assuming there was the possibility of 2 different values.
Most people would not consider the call to be the issue,
but here's an amusing bug in Oracle Sql Developer that may emulate the issue..
exec dbowner.sp1 ( p1, p2, p3); -- notes about the fields
Error report -
ORA-06550: line 1, column 362:
PLS-00103: Encountered the symbol "end-of-file" when expecting one of the following:
begin case declare end exception exit for goto if loop mod
null pragma raise return select update while with
<< close current delete fetch lock insert
open rollback savepoint set sql execute commit forall merge
pipe
06550. 00000 - "line %s, column %s:\n%s"
*Cause: Usually a PL/SQL compilation error.
*Action:
exec dbowner.sp1 ( p1, p2, p3);
-- notes about the fields
PL/SQL procedure successfully completed.
DECLARE is only used in anonymous PL/SQL blocks and nested PL/SQL blocks.
You do not need to use the DECLARE key word before you 'introduce' a new variable in a Procedure block, unless .... the procedure is a nested PL/SQL block.
This is an example of how you would declare a variable without the 'DECLARE' Key word below.
eg.;
CREATE OR REPLACE PROCEDURE EXAMPLE( A IN NUMBER, B OUT VARCHAR2 )
IS
num1 number;
BEGIN
num1:=1;
insert into a (year) values(7);
END;
This question/answer explains it better
create procedure in oracle