SQL Stored Procedure Invalid Identifier - sql

I'm getting ORA-00904 Invalid Identifier for several variables in this stored procedure when trying to compile it in oracle but cannot figure out why; All working storage events are declared at the DECLARE block of the code, and the variables from the schema are all properly defined too.
Has anyone had this error and/or knows how to fix it?
This is the DDL for the schema im working with
CREATE TABLE history
("history_id" number(4) primary key,
"history_dt" date not null,
"history_time" timestamp not null,
"booking_cost" varchar2(50) not null,
"booking_status" varchar2(50) not null
);
CREATE TABLE attendees
("attendee_id" number(8) primary key,
"attendee_name" varchar2(50) not null,
"attendee_class" number(4) not null,
"attendee_school" varchar2(50) not null,
"attendee_status" varchar2(50) not null
);
CREATE TABLE event
("event_id" number(10) primary key,
"event_name" varchar2(100) not null,
"event_location" varchar2(100) not null,
"event_size" number(4) not null,
"start_dt" date not null,
"end_dt" date not null,
"class_restriction" number(4) not null,
"school_restriction" varchar2(100) not null
);
CREATE TABLE reservation
("reservation_id" number(3) primary key,
"event" number(10) references event("event_id"),
"attendee" number(8) references attendees("attendee_id"),
"booking" number(4) references history("history_id"),
"reservation_status" varchar2(50) not null
);
These are the error messages I'm getting
Compilation failed,line 19 (15:38:10)
PL/SQL: ORA-00904: "END_DT": invalid identifierCompilation failed,line 18 (15:38:10)
PL/SQL: SQL Statement ignoredCompilation failed,line 26 (15:38:10)
PLS-00302: component 'EVENT_ID' must be declaredCompilation failed,line 26 (15:38:10)
PL/SQL: ORA-00904: "RESERVATION"."EVENT_ID": invalid identifierCompilation failed,line 26 (15:38:10)
PL/SQL: SQL Statement ignoredCompilation failed,line 36 (15:38:10)
PL/SQL: ORA-00904: "EVENT_ID": invalid identifierCompilation failed,line 35 (15:38:10)
PL/SQL: Statement ignoredCompilation failed,line 51 (15:38:10)
PL/SQL: ORA-00947: not enough valuesCompilation failed,line 51 (15:38:10)
create or replace procedure Event_Planning
(arg_event_id in number, arg_student_id in number)
IS
ws_event_name varchar(100);
ws_capacity number;
ws_event_school varchar2(4);
ws_event_class number;
past_event exception;
capacity exception;
school exception;
class exception;
BEGIN
--Test for active event
select max(event_name) into ws_event_name from event
where event_id = arg_event_id and end_dt > SYSDATE;
if ws_event_name is null
then raise past_event;
end if;
--Test for capacity
select max(event_capacity) into ws_capacity from event JOIN reservation ON event.event_id = reservation.event_id
where event_id = arg_event
and event_capacity > reservation_size;
if ws_capacity is null
then raise capacity;
end if;
--Test for restricted school
select max(school_restriction) into ws_event_school from event
where event_id = arg_event_id;
if ws_event_school = arg_school
then raise school;
end if;
--Test for restricted class
select max(class_restriction) into ws_event_class from event
where event.id = arg_event;
if ws_event_class = arg_class
then raise class;
end if;
--Update reservation table
insert into reservation values
(Seq.nextval, arg_event, arg_student);
update reservation
set reservation_size = reservation_size + 1;
--Exceptions
Exception
when past_event
then raise_application_error(-20001, 'Event has passed');
when capacity
then raise_application_error(-20002, 'Event at capacity');
when school
then raise_application_error(-20003, 'Invalid school');
when class
then raise_application_error(-20004, 'Invalid class');
END;

To make it more likely to have your questions answered, share everything.
That includes, the actual error messages. And if you REALLY want to be nice, include the TABLE DDL (and even some data) for your EVENT and RESERVATION tables.
I was too 'lazy' to guess what yours looked like, and just changed your queries to dummy tables to replicate the issue.
You haven't declared
ws_school
arg_school
ws_class
arg_class
When you compile, the compiler will return the line number and curpos of your issue. You're referring to things the db doesn't know about.
Recommendations
Don't hard code the data type definitions for your variables. Because, tables CAN and WILL change.
Instead, make them dynamic.
So, instead of saying
WS_SCHOOL VARCHAR2(4);
do something like
WS_SCHOOL TABLE.COLUMN%TYPE;
Then when your tables change, your code won't necessarily break.

By default, Oracle identifiers such as table and column names are case-insensitive, so for example you can
select dummy, DUMMY, Dummy
from dual;
However, double-quoting is also available to allow you to override the standard rules if you really need to:
create table demo("123/Wow!" number);
SQL> desc demo
Name Null? Type
----------------------------------------- -------- ----------------------------
123/Wow! NUMBER
Your tables history, attendees, event etc have case-sensitive, lowercase column names due to the double quoting, so you have to follow the same convention whenever you use them:
SQL> select count(event_id) from event;
select count(event_id) from event
*
ERROR at line 1:
ORA-00904: "EVENT_ID": invalid identifier
SQL> select count("event_id") from event;
COUNT("EVENT_ID")
-----------------
0
1 row selected.
Unless there is some important reason to do this, it would be simplest to recreate the tables without double-quoted column names.
(Also, reservation has an "event" column, not "event_id". There may be other typos like this - I haven't checked the whole thing.)

That doesn't need to use end_date on filters, because event_id is a primary key.
select "event_name" into ws_event_name
from event
where "event_id" = arg_event_id;
That looks so confuse to know, where the following columns come from: ---=^^^=---
-- event_capacity
-- reservation_size
select max("event_size") into ws_capacity
from event
join reservation
on event."event_id" = reservation."event"
where "event_id" = arg_event_id
and "event_size" > count("reservation_id");
Syntax error for event.id, it must event_id
select "class_restriction" into ws_event_class
from event
where "event_id" = arg_event_id;
Insert into reservation table:
select count(*) into reserve_count
from reservation
where "event" = arg_event_id
and "attendee" = arg_studen_id;
if reserve_count = 0
then
insert into reservation values
(Seq.nextval, arg_event_id, arg_student_id, null, "R");
end if;
--- note: that needs to declare reserve_count
Use count() to populate attendees, then no need to update reservation table.
-- update reservation
-- set reservation_size = reservation_size + 1;
reservation table:
CREATE TABLE reservation
("reservation_id" number(13) primary key,
"event" number(10) references event("event_id"),
"attendee" number(8) references attendees("attendee_id"),
"booking" number(10) references history("history_id"),
"reservation_status" varchar(1) not null
);
To merge as a single query:
select count(*), "event_name", "class_restriction"
into event_count, ws_event_name, ws_event_class
from event
where "event_id" = arg_event_id;
-- note: that needs to declare event_count

Related

sql oracle - constraint on 2 columns from different tables

I have designed a ticket system booking for flights. I want to add a constraint such that the number of tickets you can insert to be less than number of seats from a flight plane.
Let's say I inserted a flight with a plane with 10 seats. I can insert only 10 tickets for that particular flight. Otherwise, an error message should appear.
I tried to make a trigger using the count function on flight number.
CREATE OR REPLACE TRIGGER trg_ticket_BRIU
BEFORE INSERT OR UPDATE ON Ticket
FOR EACH ROW
DECLARE
l_numberofseats flight.numberofseats%type;
BEGIN
select numberofseats into l_numberofseats
from flight
where flightnumber=:new.flightnumber;
IF :new.count(flightnumber) > l_numberofseats
THEN
raise_application_error(-2000, 'Not enough seats');
END IF;
END;
but I get this error
Trigger TRG_TICKET_BRIU compiled
LINE/COL ERROR
--------- -------------------------------------------------------------
8/5 PLS-00049: bad bind variable 'NEW.COUNT'
Errors: check compiler log
Personally, I would add an AIRCRAFT and a SEAT table:
CREATE TABLE aircraft (
id NUMBER
GENERATED ALWAYS AS IDENTITY
CONSTRAINT aircraft__id__pk PRIMARY KEY,
tail_number VARCHAR2(6)
NOT NULL
CONSTRAINT aircraft__tn__u UNIQUE
CONSTRAINT aircraft__tn_chk CHECK(
REGEXP_LIKE(
tail_number,
'[A-Z]\d{1,5}|[A-Z]\d{1,4}[A-Z]|[A-Z]\d{1,3}[A-Z]{2}'
)
),
manufacturer VARCHAR2(20)
NOT NULL,
model VARCHAR2(20)
NOT NULL,
airline_id CONSTRAINT aircraft__aid__fk REFERENCES airline(airline_id)
NOT NULL
);
CREATE TABLE seat (
id NUMBER
GENERATED ALWAYS AS IDENTITY
CONSTRAINT seat__id__pk PRIMARY KEY,
aircraft_id CONSTRAINT seat__aid__fk REFERENCES aircraft(id)
NOT NULL,
seat_row VARCHAR2(3)
NOT NULL,
seat_column NUMBER
NOT NULL,
CONSTRAINT seat__aid_r_c__u UNIQUE (aircraft_id, seat_row, seat_column)
);
Then your flight table would reference the aircraft:
CREATE TABLE flight (
id NUMBER
GENERATED ALWAYS AS IDENTITY
CONSTRAINT flight__id__pk PRIMARY KEY,
aircraft_id CONSTRAINT flight__aid__fk REFERENCES aircraft(id)
NOT NULL
-- ...
);
And the ticket would reference a flight and a seat:
CREATE TABLE ticket (
id NUMBER
GENERATED ALWAYS AS IDENTITY
CONSTRAINT ticket__id__pk PRIMARY KEY,
flight_id CONSTRAINT ticket__fid__fk REFERENCES flight(id)
NOT NULL,
seat_id CONSTRAINT ticket__sid__fk REFERENCES seat(id)
NOT NULL,
-- ...
CONSTRAINT ticket__fid_sid__u UNIQUE (flight_id, seat_id)
);
Then you can never sell a seat that does not exist on an aircraft and do not need to count the maximum number of tickets and compare it to seats (and the seat has added attributes like its location on the plane that can be displayed on the ticket).
All you need then is to ensure the referential consistency that, for a ticket, the flight and the seat are on the same aircraft; which can be done with a trigger:
CREATE TRIGGER ticket_check_seat_on_flight
BEFORE INSERT OR UPDATE ON ticket
FOR EACH ROW
DECLARE
is_valid NUMBER(1);
BEGIN
SELECT 1
INTO is_valid
FROM flight f
INNER JOIN seat s
ON (f.aircraft_id = s.aircraft_id)
WHERE f.id = :NEW.flight_id
AND s.id = :NEW.seat_id;
EXCEPTION
WHEN NO_DATA_FOUND THEN
RAISE_APPLICATION_ERROR(
-20000,
'Flight and seat are on different aircraft.'
);
END;
/
db<>fiddle here
You can use an AFTER STATEMENT trigger:
CREATE TRIGGER ticket__check_number_of_seats
AFTER INSERT OR UPDATE OR DELETE ON ticket
DECLARE
is_invalid NUMBER(1,0);
BEGIN
SELECT 1
INTO is_invalid
FROM flight f
INNER JOIN (
SELECT flight_id,
COUNT(*) AS tickets_sold
FROM ticket
GROUP BY flight_id
) t
ON f.id = t.flight_id
WHERE t.tickets_sold > f.number_of_seats;
RAISE_APPLICATION_ERROR(
-20000,
'Too many tickets sold for flight.'
);
EXCEPTION
WHEN NO_DATA_FOUND THEN
NULL;
END;
/
It could be made more efficient by using a compound trigger to collate, for each row, the flight_id values into a collection and then, after the statement, only checking the number of tickets for those flights; however, I'll leave that extension as an exercise for the OP.
db<>fiddle here
As others indicated there is no :new.count column. This is because :new (and :old) create a pseudo-row containing exactly the same columns as the table definition. Further you will get a Mutating exception as what you need to count in the flight_number from tickets. However, since that is the table causing he trigger to fire you cannot reference it. So what to do: create a compound trigger, and a supporting Type (nested table). Within it use the after row section to capture the flight_numbers processed. Then in the after statement section you can select count of tickets for each flight. If that count > 0 then raise your exception. ( see Demo )
create type flight_tickets_ntt
is table of integer;
create or replace trigger trg_ticket_ciu
for update or insert on tickets
compound trigger
l_flights flight_tickets_ntt := flight_tickets_ntt();
after each row is
begin
if :new.flight_number not member of l_flights then
l_flights.extend ;
l_flights(l_flights.count) := :new.flight_number;
end if;
end after each row;
after statement is
l_flight_cnt flight.flight_number%type;
begin
select count(*)
into l_flight_cnt
from flight f
where f.number_of_seats <
( select count(*)
from tickets t
where t.flight_number in
( select *
from table (l_flights)
)
);
if l_flight_cnt > 0 then
raise_application_error(-20000, 'Not enough seats');
end if;
end after statement;
end trg_ticket_ciu;
There remains a you need to handle: What happens if an update changes the flight number or perhaps (missing column) the data of the flight.

Making a trigger to not create an insurance policy for a driver that has been involved in an accident

Hello I am brand new to triggers in SQL and need some help with one. I am working with 3 tables involving drivers, car accidents, and insurance policy. What I am trying to do is create a trigger that will not allow insurance policies to be able to be made for drivers involved in an accident.
Here is what I have tried so far:
CREATE TABLE insurance_policy(
id INT,
ssn_driver INT,
expiration_date DATE,
PRIMARY KEY (id)
);
CREATE TABLE accident(
id INT,
ssn_driver INT,
accident_date DATE,
details VARCHAR2(64),
PRIMARY KEY (id),
FOREIGN KEY (id) REFERENCES insurance_policy,
FOREIGN KEY (ssn_driver) REFERENCES driver
);
CREATE TABLE driver(
ssn_driver INT,
name VARCHAR2(64),
age INT CHECK (age>15),
PRIMARY KEY(ssn_driver)
);
CREATE TRIGGER no_insurance_policy
AFTER INSERT OR UPDATE ON insurance_policy
FOR EACH ROW
BEGIN
IF EXISTS (select ssn_driver FROM Inserted INNER JOIN accident)
BEGIN
rollback transaction
raiserror ('some message', 16, 1)
END
END
This doesn't compile, but I'm just confused on how to proceed from here. Can anyone help me out with creating this trigger?
EDIT: Here is the error
Error starting at line : 31 in command -
BEGIN
IF EXISTS (select ssn_driver FROM Inserted INNER JOIN accident)
BEGIN
rollback transaction
raiserror ('some message', 16, 1)
END
END
Error report -
ORA-06550: line 2, column 58:
PLS-00103: Encountered the symbol "JOIN" when expecting one of the following:
) , with group having intersect minus start union where
connect
06550. 00000 - "line %s, column %s:\n%s"
*Cause: Usually a PL/SQL compilation error.
*Action:
First, you need to do BEFORE not AFTER insert. Then, your syntax is not even Oracle. Here is approximately what you need to do. I have not tested it.
CREATE TRIGGER no_insurance_policy
BEFORE INSERT OR UPDATE ON insurance_policy
FOR EACH ROW
DECLARE
v_accidentCout NUMBER(10);
BEGIN
Select Count(*) Into v_accidentCout
From accident
Where ssn_driver = old.ssn_driver;
If v_accidentCout > 0 Then
raise_application_error(-12345, 'Driver has accidents');
End If;
END;
/
I would leave commit/rollback to the block that calls insert/update.

Why is my PL/SQL trigger raising an "Error(2,2): PL/SQL: Statement ignored" and an "Error(2,5): PLS-00204: function or pseudo-column 'EXISTS' " error?

I am attempting to write a trigger which prevents the insertion into my TA (teaching assistant) table if the student is already taking the class for which they're attempting to become a TA. From what I understand the best way to do this (other than a unique constraint, this has to be a trigger) is through the use of rollback, and I'm also using raiserror.
create or replace trigger CheckTA
after insert
on TA for each row
begin
if exists (select * from Enrolls where Student_ID = :new.Student_ID and Course_ID = :new.Course_ID) then
rollback;
raiserror('TA enrolled in course as student');
end if;
end;
Upon creating the trigger, I'm met with the following errors:
Error(2,2): PL/SQL: Statement ignored
Error(2,5): PLS-00204: function or pseudo-column 'EXISTS' may be used inside a SQL statement only
The trigger still gets created, but it doesn't trigger when improper values are inserted into TA.
Tables:
TA
Create table TA
(
Student_ID int references Student(Student_ID),
Course_ID int references Course(Course_ID),
Courses_taught varchar2(250),
Office_hours varchar2(25)
);
Student
create table Student
(
Student_ID int primary key,
Name varchar2(50),
Start_began int,
Semester_began varchar2(50),
GPA int,
Degree_status varchar2(25),
Degree_type varchar2(50),
Courses_Taken varchar2(250),
JI_list varchar2(250),
Profile_status varchar2(50)
);
Course
create table Course
(
Course_ID int primary key,
Course_Name varchar2(25)
);
Enrolls
create table Enrolls
(
Student_ID int references Student(Student_ID),
Course_ID int references Course(Course_ID)
);
Stored Procedure
This is the SP I use to insert TA values that should trigger the trigger. It doesn't raise errors but I'll put it here in case it's relevant.
create or replace procedure addTA (s_id int, c_id int, course varchar2)
as
begin
insert into TA (Student_ID,Course_ID,Courses_taught)
values (s_id,c_id,course);
end;
Honestly I'm not quite sure what these errors mean, let alone what's causing them, but still I've tried messing with the syntax of raiserror as well as replacing it with raise_application_error with no luck. If anyone could help me resolve or at least explain these errors it would be greatly appreciated. And of course if there is anything obviously wrong with my trigger please let me know.
The error says "function or pseudo-column 'EXISTS' may be used inside a SQL statement only", meaning that you only can use EXISTS inside a SQL statment, while you are using in in a PL/SQL statement.
If you need to check for the existence of some records, you can try something like this:
vNum number;
...
select count(1)
into vNumber
from Enrolls
where Student_ID = ...
if vNumber > 0 then
...
else
...
end if;

Insert fails due to "column not allowed here" error

I am a beginner with SQL. I have created 4 tables and added data to my SHIP table. I am having some issues with inserting data into the CRUISE table. I get the error message at the bottom.
I have researched and can not figure out what i am doing wrong. Is there an issue with my sequence and/or trigger that is not allowing me to do this or is my syntax in the CREATE TABLE CRUISE causing the error? Everything i have done has been successful up until trying to insert the first column into the CRUISE table.
The tables:
CREATE TABLE SHIP
( Ship_Name VARCHAR2(100) PRIMARY KEY,
Ship_Size INTEGER,
Ship_Registry VARCHAR2(50),
Ship_ServEntryDate INTEGER,
Ship_PassCapacity INTEGER,
Ship_CrewCapacity INTEGER,
Ship_Lifestyle VARCHAR2(40),
CONSTRAINT Size_ck CHECK (Ship_Size > 0),
CONSTRAINT Registry_ck CHECK (Ship_Registry IN ('Norway','Liberia','The Netherlands','Bahamas'))
)
CREATE TABLE CRUISE (
Cruise_ID INTEGER Primary Key,
Ship_Name VARCHAR(100),
Cruise_DeptDate DATE NOT NULL,
Cruise_DeptCity VARCHAR(80) NOT NULL,
Cruise_Duration INTEGER,
FOREIGN KEY (Ship_Name) REFERENCES SHIP(Ship_Name)
)
CREATE TABLE PASSENGERS (
Pass_ID INTEGER PRIMARY KEY,
Pass_Name VARCHAR(100) NOT NULL,
Pass_City VARCHAR(80),
Pass_Telephone VARCHAR(15),
Pass_NextOfKin VARCHAR(100)
)
CREATE TABLE RESERVATIONS (
Pass_ID INTEGER NOT NULL,
Cruise_ID INTEGER NOT NULL,
Res_TotalCost NUMERIC(9,2),
Res_BalanceDue NUMERIC(9,2),
Res_SpecialRequest VARCHAR(30),
Res_Room VARCHAR(10),
FOREIGN KEY (Pass_ID) REFERENCES PASSENGERS(Pass_ID),
FOREIGN KEY (Cruise_ID) REFERENCES CRUISE(Cruise_ID),
CONSTRAINT Cost_ck CHECK (Res_TotalCost >= 0),
CONSTRAINT BalanceDue_ck CHECK (Res_BalanceDue >= 0),
CONSTRAINT SpecialRequest_ck CHECK (Res_SpecialRequest IN ('Vegetarian','Vegan','Low salt','Gluten free','Kosher','Other'))
)
The sequence/trigger is an attempt to auto number Cruise_ID.
Create SEQUENCE cruise_id_sq
START WITH 1
INCREMENT BY 1;
CREATE OR REPLACE TRIGGER cruise_id_t
BEFORE INSERT
ON CRUISE
REFERENCING NEW AS NEW
FOR EACH ROW
BEGIN
if(:new.Cruise_ID is null) then
SELECT cruise_id_sq.nextval
INTO :new.Cruise_ID
FROM dual;
end if;
END;
ALTER TRIGGER cruise_id_t ENABLE;
Inserting into SHIP is okay....
INSERT INTO SHIP
(Ship_Name, Ship_Size, Ship_Registry,Ship_ServEntryDate, Ship_PassCapacity,Ship_CrewCapacity,Ship_Lifestyle)
Values ('Carribean Princess',142000,'Liberia',1000,3100,1181,'Contemporary');
INSERT INTO SHIP
(Ship_Name, Ship_Size, Ship_Registry,Ship_ServEntryDate, Ship_PassCapacity,Ship_CrewCapacity,Ship_Lifestyle)
Values ('Carribean Sunshine',74000,'Norway',1992,1950,760,'Premium');
INSERT INTO SHIP
(Ship_Name, Ship_Size, Ship_Registry,Ship_ServEntryDate, Ship_PassCapacity,Ship_CrewCapacity,Ship_Lifestyle)
Values ('Ship of Dreams',70000,'Liberia',2004,1804,735,'Contemporary');
INSERT INTO SHIP
(Ship_Name, Ship_Size, Ship_Registry,Ship_ServEntryDate, Ship_PassCapacity,Ship_CrewCapacity,Ship_Lifestyle)
Values ('Sunshine of the Seas',74000,'The Netherlands',1990,2354,822,'Luxury');
Inserting into CRUISE fails...
INSERT INTO Cruise
(Ship_Name, Cruise_DeptDate,Cruise_DeptCity,CruiseDuration)
Values ('Sunshine of the Seas',25-may-15,'Miami',10);
Error starting at line : 1 in command - INSERT INTO Cruise (Ship_Name,
Cruise_DeptDate,Cruise_DeptCity,CruiseDuration) Values ('Sunshine of
the Seas',25-may-15,'Miami',10) Error at Command Line : 3 Column : 35
Error report - SQL Error: ORA-00984: column not allowed here
00984. 00000 - "column not allowed here"
*Cause:
*Action:
Oracle thinks that 25-may-15 is the expression 25 minus may minus 15. In looking up the value for may Oracle finds that there is nothing there. Thus the error.
You can, but probably don't want to, quote it like so, '25-may-15'. This will make a string that may or may not be implicitly converted to a date, depending on the settings of NLS_DATE_FORMAT and or NLS_TERRITORY.
To form a date independent of session setting one can use the TO_DATE function with explicit date format, to_date('25-may-15', 'DD-Mon-YY'). Another option is a date literal, date '2015-05-25', which is always YYYY-MM-DD no matter the session settings..

Error: numeric or value errors

I know this error issue was been addressed before, but I can't seem to find any relevant solution so I'm posting this question.
create table subscribers(
num_s number(6,0) ,
name varchar2(30) constraint nameM not null,
surname varchar2(20),
town varchar2(30),
age number(3,0) ,
rate number(3,0) ,
reduc number(3,0) ,
CONSTRAINT subscriber_pk primary key (num_s),
constraint age_c check (age between 0 and 120)
);
create or replace type copy_bookT as object(
num number(6),
loancode varchar2 (10),
book_ref ref bookT
);
create table copy_books of copy_bookT(
constraint pk_cb primary key (num),
constraint chk_st check (loancode in('Loan', 'Not')),
loancode default 'Loan' not null
);
create table Lending(
cb_num number(6),
sb_num number(6),
date_L date,
constraint fk_cb foreign key (cb_num) references copy_books(num),
constraint fk_sb foreign key (sb_num) references Subscribers(num_s)
);
create or replace trigger chk_DateL
for insert or update on lending
COMPOUND TRIGGER
--declare
L_Date int;
avail varchar2(10);
subtype copy_booksRec is lending%ROWTYPE;
type copied_bks is table of copy_booksRec;
cbks copied_bks := copied_bks();
before each row is
begin
cbks.extend;
cbks(cbks.last).cb_num := :new.cb_num;
cbks(cbks.last).sb_num := :new.sb_num;
end before each row;
before statement is
begin
for i in cbks.first .. cbks.last loop
select loancode into avail from copy_books where num = cbks(i).cb_num;
select count(date_L) into L_Date from lending where sb_num = cbks(i).sb_num and date_L = cbks(i).date_L;
if (L_Date = 0 and avail = 'Loan') then
update copy_books set loancode = 'Not' where num = cbks(i).cb_num;
cbks.delete;
-- cbks(i).date_L := cbks(i).date_L;
else
dbms_output.put_line('You can only make ONE LOAN at a time! You have already loaned a book on ' || L_Date);
cbks.delete;
end if;
end loop;
-- FORALL i IN cbks.first .. cbks.last
-- insert into lending values cbks(i);
cbks.delete;
end before statement;
end chk_DateL;
/
show errors
It all compiles successfully, but when I try to insert a sample record like:
insert into lending values (2, 700, '10-MAR-14');
it raises a numeric error which comes from the trigger line 18. I don't know what needs fixing despite my efforts.
You should not count on Oracle's default date format to translate your string literal to a date value , you should define the format you're using explicitly:
insert into lending values (2, 700, to_date('10-MAR-14', 'DD-MON-YY'));
While the date format issue is a valid point, that isn't causing your error. It's coming from line 18, which is the for ... loop line:
before statement is
begin
for i in cbks.first .. cbks.last loop
You've got cbks being extended and populated from the before row part of the trigger. When the before statement part fires, cbks is empty, as the row-level trigger hasn't fired yet. It's the first and last references that are throwing the ORA-06502: PL/SQL: numeric or value error error.
You can demonstrate the same thing with a simple anonymous block:
declare
type my_type is table of dual%rowtype;
my_tab my_type := my_type();
begin
for i in my_tab.first .. my_tab.last loop
null;
end loop;
end;
/
ORA-06502: PL/SQL: numeric or value error
ORA-06512: at line 5
SQL Fiddle; you can see you can avoid it by adding an extend, but that doesn't really help you in your version, since you seem to want the row values. (You can eliminate the error in your code with an extend, but it's unlikely to do what you want still).
I'm really not sure what you're trying to achieve here, so I don't really have any advice on what you need to do differently.
as Mureinik already told, Oracle does not know about how to transform your varchar2 into date datatype and you should use date explicitly. But instead of making to_date use date literal - in my opinion it is more clear than using of to_date function
insert into lending values (2,700,date '2014-03-10');
by the way, you can simply change your NLS settings by altering the current session and installing the date format you need