Unable to create trigger in Oracle/iSQL - sql

I made a table student, in which there is an attribute evaluation.
Now i am making a trigger in which i want that if i insert a value of zero in evaluation then a trigger should fire and store some values in audit_table.
here is my code
Create table Student ( Student_Id Number(8,2), Student_Name Varchar2(50), Gender Varchar(8), Telephone_No Number(15), Location Varchar2(200), Education Varchar2(100), Company_name Varchar2(200), No_of_attempt Number(2), Offering_Id Number(3) , EVALUATION NUMBER(2), Primary Key (Student_Id), Constraint fk_Oid Foreign Key (Offering_Id) References Course(Offering_Id) );
And now the audit table code
CREATE TABLE AUDIT_TABLE ( STUD_NAME VARCHAR2(100), COURSE_NAME
VARCHAR2(100), INSTRUCTOR_NAME VARCHAR2(200), EVALUATION NUMBER (2)
);
Now my main question is this my trigger not working
create trigger tr_student
after insert or update on student
for each row
declare
s_name student.student_name%type;
s_eval student.evaluation%type;
s_offr_id student.offering_id%type;
s_course_name student.student_name%type;
s_instr student.student_name%type;
begin
if evaluation == 0;
s_offr_id =(select offering_id from student where evaluation==0);
s_eval =0;
s_name =(select student_name from student where evaluation==0);
s_course_name =(select course_name from course where offering_id==s_offr_id);
s_instr=(select name from instructor where offering_id==s_offr_id);
insert into AUDIT_TABLE values(s_name,s_course,s_instr,s_eval);
end;
Is there some problem with my trigger?

This is not possible:
s_name =(select student_name from student where evaluation==0);
Change it to
select student_name into s_name from student where evaluation = 0;
Note there are two problems. First, you need into to select a value into a variable. Second, the comparison operator in SQL is only a single =.
The same goes for
if evaluation == 0;
..
end;
It should be
if :new.evaluation = 0 then
...
end if;
So there, the you forgot the then and end if, the comparison operator is wrong and you need :new.fieldname to get the value of the field, instead of a local variable.
The assignment operator in PLSQL is :=, so
s_eval =0;
should be changed to
s_eval := 0;
It seems you need to grab the schoolbook again and do some more reading. :)

Related

SQL: Can't create function returning table. "Table is not valid at this position, expecting: bit, bool, boolean, ...."

I can't figure out what's wrong with this SQL function... in "returns table" it complains that "Table is not valid at this position, expecting: bit, bool, boolean, ....". Does anyone know?
create table department(
dept_name varchar(20),
n_prof int,
budget numeric(10,2),
primary key (dept_name)
);
create table instructor(
ID char(5),
name varchar(20),
dept_name varchar(20),
salary numeric(8,2),
primary key (ID),
foreign key (dept_name) references department (dept_name)
);
create function instructors (dept_name char(20))
returns TABLE
as
return
select ID, name, dept_name, salary
from instructor
where instructor.dept_name=dept_name;
Based on error, I guess you are using MYSQL database.
As per documentation on user defined functions in MySQL
you can only return values of type {STRING|INTEGER|REAL|DECIMAL}
CREATE [AGGREGATE] FUNCTION function_name RETURNS {STRING|INTEGER|REAL|DECIMAL}
SONAME shared_library_name
If you want to read a select resultset you have to define a procedure but not function.
DELIMITER //
DROP PROCEDURE IF EXISTS myProcedure //
CREATE PROCEDURE
myProcedure( dept_name char(20) )
BEGIN
select ID, name, dept_name, salary
from instructor
where instructor.dept_name=dept_name;
;
END
//
DELIMITER ;
And you can call procedure like
call myProcedure( 'CSE' )
That returns implicit objects based on the statements used in the procedure.
Please use below query.
USE Your_Database
create table dbo.department(
dept_name varchar(20),
n_prof int,
budget numeric(10,2),
primary key (dept_name)
);
GO
create table dbo.instructor(
ID char(5),
name varchar(20),
dept_name varchar(20),
salary numeric(8,2),
primary key (ID),
foreign key (dept_name) references department (dept_name)
);
GO
create function dbo.instructors (#dept_name char(20))
returns TABLE
as
return
select ID, name, dept_name, salary
from dbo.instructor
where instructor.dept_name=#dept_name;
You have used dept_name which is already existing in your table column so use #dept_name instead of that.
Please use GO statement to separate the each transaction otherwise you will get error.
Msg 111, Level 15, State 1, Line 19 'CREATE FUNCTION' must be the
first statement in a query batch. Msg 137, Level 15, State 2, Line 25
Must declare the scalar variable "#dept_name".

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;

sql error 04098 invalid trigger

I need some assistance with troubleshooting the trigger that I'm trying to create/use for logging updates and inserts on a table.
I'm using a customers_history table to track all the changes being made on the customers table.
CREATE TABLE customers (
custID INTEGER PRIMARY KEY,
custFName VARCHAR2(30),
custLName VARCHAR2(30),
custState CHAR(20),
custZip NUMBER(5)
);
-- log inserts and updates on customers table
CREATE TABLE customers_history (
histID INTEGER PRIMARY KEY,
cID INTEGER,
cFName VARCHAR2(30),
cLName VARCHAR2(30),
cState CHAR(20),
cZip NUMBER(5)
);
Also, for the histID I'm using a sequence to auto increment the histID on customers_history table.
CREATE SEQUENCE ch_seq
MINVALUE 1
START WITH 1
INCREMENT BY 1;
CREATE OR REPLACE TRIGGER audit_customers
BEFORE UPDATE
OR INSERT ON customers
FOR EACH ROW
BEGIN
INSERT INTO customers_history(histID,cID,cFName,cLName,cState,cZip)
VALUES(ch_seq.nextval,:NEW.custID,:NEW.custFName,:NEW.custLName,
:NEW.custState,:NEW.custZip);
END;
/
I have been inserting two rows on customers prior to creating the trigger, and they work fine. After I create the trigger, it will not allow me to insert anymore rows on customers and it also throws the ORA-04098: trigger 'SYSTEM.AUDIT_CUSTOMERS' is invalid and failed re-validation 04098. 00000 - "trigger '%s.%s' is invalid and failed re-validation" error message.
I've tried to see if there is any code errors using select * from user_errors where type = 'TRIGGER' and name = 'audit_customers'; and it returned no lines. Not sure if that helps or not. Thanks.
you have created your trigger for multiple DML operations (Insert and Update) so you need to specipy the DML operation by using IF INSERTING THEN....END IF; and IF UPDATING THEN....END IF; for example:
CREATE OR REPLACE TRIGGER audit_customers
BEFORE UPDATE
OR INSERT ON customers
FOR EACH ROW
BEGIN
IF INSERTING THEN
INSERT INTO customers_history(histID,cID,cFName,cLName,cState,cZip)
VALUES(ch_seq.nextval,:NEW.custID,:NEW.custFName,:NEW.custLName,
:NEW.custState,:NEW.custZip);
END IF;
END;
/
I went through and changed a couple things and it seems to work for both insert and update operations. I dropped the tables, sequence, and trigger, then did the tried the following code and it works now. Thank you all for your time and inputs!
CREATE TABLE customers (
custID INTEGER,
custFName VARCHAR2(30),
custLName VARCHAR2(30),
custState CHAR(20),
custZip NUMBER(5)
);
CREATE TABLE customers_history (
histID INTEGER,
cID INTEGER,
cFName VARCHAR2(30),
cLName VARCHAR2(30),
cState CHAR(20),
cZip NUMBER(5)
);
CREATE OR REPLACE TRIGGER audit_customers
BEFORE UPDATE
OR INSERT ON customers
FOR EACH ROW
BEGIN
INSERT INTO customers_history(
histID,
cID,
cFName,
cLName,
cState,
cZip
)
VALUES(
ch_seq.nextval,
:new.custID,
:new.custFName,
:new.custLName,
:new.custState,
:new.custZip
);
END;
/
I used the same sequence code as before, added a couple of rows, and it worked. Then I altered the two tables, by adding the primary keys,
ALTER TABLE customers ADD PRIMARY KEY(custID);
ALTER TABLE customers_history ADD PRIMARY KEY(histID);
inserted a couple other columns, modified a few rows, and it still worked. I'm a happy camper, although I'm not certain what or how it actually got fixed.

Oracle - Insert Stored Procedure Foreign Key

Instructions:
Create two tables, named employees and departments. Preface the table names with your initials. Link the two tables (foreign key) by a column called dept. Make up a few column names for each table.
Employees Table:
create table bsemployees(
dept number primary key,
empName varchar2(20),
salary number
);
Departments Table:
create table bsdepartments(
dept number references bsemployees(dept),
deptName varchar2(20)
);
Write the following stored procedures:
• Insert a row into the employees table. If the department does not exist. Insert it into the departments table.
create or replace procedure sp_employees(
a_dept IN number,
a_empName IN varchar2,
a_salary IN number
)
as
vCount number;
BEGIN
sp_check_dept(a_dept,vCount);
insert into bsemployees values(a_dept, a_empName, a_salary);
if vCount = 0 then
dbms_output.put_line('**DEPT DOES NOT EXIST**');
insert into bsdepartments (dept, deptName) values(a_dept, NULL);
end if;
END;
/
create or replace procedure sp_check_dept(
a_dept IN number,
vCount OUT number
)
as
BEGIN
select count(*)
into vCount
from bsdepartments
where dept = a_dept;
end;
/
• Insert a row into the departments table.
create or replace procedure sp_departments(
a_dept IN number,
a_deptName IN varchar2
)
as
BEGIN
insert into bsdepartments values(a_dept, a_deptName);
END;
/
I've got it pretty much all down for this assignment except for the fact that when I try to insert a row into the departments table I am getting a integrity constraint - parent key not found error.
If I do execute sp_employees(5, 'John Doe', 90000); It will display ***DEPT DOES NOT EXIST*** and will go ahead and insert the data into bsemployees and insert the dept# into bsdepartments and the deptName will be left blank based on my if-then statement. Doing a select(*) shows me this.
However if I go ahead and do execute sp_departments(1, 'human resources'); to place a row into departments I get the parent key error. I understand that I am trying to insert something that has no parent key but I do not know how to fix it.
Your table design isn't quite correct - the dept primary key needs to be added as a foreign key to employee (not as the primary key), and employee should have its own primary key:
create table bsdepartments(
dept number primary key,
deptName varchar2(20)
);
create table bsemployees(
empName varchar2(20) primary key,
dept number references bsdepartments(dept),
salary number
);
You can then do the 'add if not exists' logic in the check_dept proc:
create or replace procedure sp_check_dept(
a_dept IN number
)
as
vCount number
BEGIN
select count(*)
into vCount
from bsdepartments
where dept = a_dept;
if (vCount = 0) then
dbms_output.put_line('**DEPT DOES NOT EXIST**');
insert into bsdepartments (dept, deptName) values(a_dept, NULL);
end if;
end;
Which then simplifies the employee insertion proc as it should be guaranteed of a department:
create or replace procedure sp_insertEmployee(
a_dept IN number,
a_empName IN varchar2,
a_salary IN number
)
as
BEGIN
sp_check_dept(a_dept);
insert into bsemployees values(a_dept, a_empName, a_salary);
END
Notes
Recommend that you name the procs in alignment with their purpose, e.g. insertEmployee vs just employees
As you've noted, the problem with the 'add if not exists' approach is that you do not have sufficient data to completely populate the department table, hence the null column (but this is what your lecturer asked for)
Your realation to table department is bad. It should linked as below
create table bsdepartments(
dept number primary key,
deptName varchar2(20)
);
and it should be linked to employee table
create table bsemployees(
dept number references bsdepartments(dept),
empName varchar2(20),
salary number
);
Then if you try inserting execute sp_departments(1, 'human resources'); it will execute
an then you have to insert the employee.
Here the employee is related to department not the department is related to employee.

SQL trigger to limit the number of users

I'm still learning how to use SQL, and I need some help creating this database.
I've created the following tables:
create table Worker
(Num_Worker number(20) PRIMARY KEY,
Name varchar2(30),
ID number(8),
Password varchar2(20));
create table Area
(Code_Area number(10) PRIMARY KEY,
Name varchar2(30),
Current_workers number(2)
Max_workers number(2));
create table Timetable
(ID_Timetable number(10) PRIMARY KEY,
Time_Entrance date,
Time_Exit date,
Code_Area number(10),
Num_Worker number(20),
Foreign Key (Num_Worker) references Worker(Num_Worker),
Foreign Key (Code_Area) references Area(Code_Area));
Supposedly, each worker can choose a area to work at, but each area has a limit or workers at the same time.
What would happen is a worker would create a new timetable, but before that timetable is created it should check the area that he chose to check if the "Current_workers" is the same value as "Max_workers", and if it is it shouldn't let it happen.
I've been trying to create a trigger for that, but I've had no luck in finding the correct syntax for it, and I'm not sure how to do it either, or if there's a better way to do it than with a trigger.
This is all I've done so far:
create trigger limit_worker_per_zone
before insert
on Timetable
for each row
as
BEGIN
if (select Current_Workers from Area) >= (select Max_workers from Area) <-Not sure...
BEGIN
???
END
END
I'd really appreciate if you can help me in this. I'll still be looking for more info myself meanwhile, but the more help the better.
CREATE TRIGGER limit_worker_per_zone
BEFORE INSERT
ON Timetable
FOR EACH ROW
DECLARE
v_total NUMBER;
BEGIN
BEGIN
SELECT max_workers - current_workers
INTO v_total
FROM Area
WHERE Code_Area = :NEW.Code_Area;
exception when no_data_found then
v_total := 1;
END;
IF v_total <= 0 THEN
raise_application_error(990000, 'workers full for this area');
END IF;
END limit_worker_per_zone;
Try this as a starting point:
CREATE OR REPLACE TRIGGER LIMIT_WORKER_PER_ZONE
BEFORE INSERT ON TIMETABLE
FOR EACH ROW
AS
nCurrent_workers NUMBER;
nMax_workers NUMBER;
BEGIN
SELECT CURRENT_WORKERS,
MAX_WORKERS
INTO nCurrent_workers,
nMax_workers
FROM AREA
WHERE CODE_AREA = :NEW.CODE_AREA;
IF nCurrent_workers = nMax_workers THEN
NULL; -- add code here to do the appropriate thing when the area is already full
ELSE
NULL; -- add code here to to the appropriate thing if the area is not full
END IF;
END LIMIT_WORKER_PER_ZONE;
I'll leave it to you to flesh this out.
Share and enjoy.