I have PL/SQL anonymous block to work with finding an employees based on their department_id. I wrote a procedure for that.
Code
CREATE OR REPLACE PROCEDURE find_employees (
p_dept_no IN NUMBER,
p_error_message OUT VARCHAR2)
AS
v_dept_no NUMBER;
dept_chk EXCEPTION;
CURSOR find_emp
IS
SELECT employee_id,
first_name,
last_name,
salary,
hire_date
FROM employees
WHERE department_id = p_dept_no;
BEGIN
-- Check if the department_id in departments table
IF Condition
THEN --Need to check the condition here
RAISE dept_chk;
END IF;
FOR i IN find_emp
LOOP
DBMS_OUTPUT.put_line (i.employee_id);
DBMS_OUTPUT.put_line (i.first_name);
DBMS_OUTPUT.put_line (i.last_name);
DBMS_OUTPUT.put_line (i.salary);
DBMS_OUTPUT.put_line (i.hire_date);
END LOOP;
EXCEPTION
WHEN dept_chk
THEN
p_error_message := 'Please enter valid department number';
END find_employees;
How to check if the department_id in departments table
Note:
On that procedure there is one input parameter p_dept_no as INPUT
and p_error_message is the output parameter.
I need to check the if the department_id is in in the departments table then automatically the records will show other wise it's showing an exception so there i need to check the condition how it's possible let me know Thanks in advance.
Given that you already scan the table, you can simply set a variable in within the loop and check its value outside.
For example:
CREATE OR REPLACE PROCEDURE find_employees(p_dept_no IN
NUMBER,p_error_message OUT VARCHAR2)
AS
v_dept_no NUMBER;
dept_chk EXCEPTION;
vEmployeeFound boolean := false; -- a boolean variable
CURSOR find_emp
IS
SELECT
employee_id, first_name, last_name, salary, hire_date
FROM
employees
WHERE
department_id = p_dept_no;
BEGIN
FOR i in find_emp
LOOP
dbms_output.put_line(i.employee_id);
dbms_output.put_line(i.first_name);
dbms_output.put_line(i.last_name);
dbms_output.put_line(i.salary);
dbms_output.put_line(i.hire_date);
vEmployeeFound := true; -- set the variable
END LOOP;
-- Check if the department_id in departments table
IF NOT vEmployeeFound THEN -- check the variable value
RAISE dept_chk;
END IF;
EXCEPTION
WHEN dept_chk THEN
p_error_message:='Please enter valid department number';
END find_employees;
Related
I am querying APEX_COLLECTION view to see if a record exists and when it does not, I am getting NO_DATA_FOUND exception. To handle that I used an anonymous block:
BEGIN
SELECT c001, c002 INTO l_var1, l_var2
FROM APEX_COLLECTION
WHERE collection_name = 'TEST' AND c003='test';
EXCEPTION
WHEN NO_DATA_FOUND
l_var1 := NULL;
l_var2 := NULL;
END;
Is there a better way to handle this?
If you just want to see if a record exists, you can use de COUNT() function. In this way, it is not necessary to use anonymous blocks or NO_DATA_FOUND excepcion. The COUNT function always returns a value.
SELECT COUNT(*)
INTO l_count
FROM APEX_COLLECTION
WHERE collection_name = 'TEST' AND c003='test';
IF l_count > 0 THEN
-- Do something, the record exits
ELSE
-- Do something, the record does not exit
END IF;
Did not find better solution to my issue besides using anonymous block and capturing a NO_DATA_FOUND exception.
Use a predefined cursor and you won't be bothered with the NO_DATA_FOUND exception.
DECLARE
cursor c_apex_coll
is
SELECT c001, c002
FROM APEX_COLLECTION
WHERE collection_name = 'TEST' AND c003='test';
l_var1 varchar2(256);
l_var2 varchar2(256);
BEGIN
open c_apex_coll;
fetch c_apex_coll into l_var1, l_var2;
close c_apex_coll;
END;
I want to make my item id auto increment, so that user cannot insert any number. It is for ordinal numbers of inovice items, so there can't be any gaps.
Table:
TABLE_NAME (id NUMBER GENERATED ALWAYS AS IDENTITY( NOCACHE), name VARCHAR2(10), PRIMARY KEY (id));
Then I created a process with PL/SQL code:
IF :P27_ID IS NULL THEN
SELECT ID.NEXTVAL INTO :P27_ID FROM DUAL;
END IF;
But if I delete an item, his value is lost and next entered item won't have his id.
Im trying to write a procedure that updates the domain of an email (example: converting Email123#gmail.com into Email123#hotmail.com when i pass 2 strings gmail.com and hotmail.com) while having a cursor in my procedure
create of replace procedure pr_update_email
(Old_Email Varchar2, New_Email Varchar2)
As
V_OldDomain Varchar2(50);
Cursor C_Domains IS Select Email_Address
From Customer
where Email_Address Like '%#'||Old_Email;
Begin
Open C_Domains;
Fetch C_Domains INTO V_OldDomain;
While C_Domains %Found loop
Update Customer
Set Email_Address = regexp_replace(Email_Address, '^(.*#.*)'||Old_Email||'\1'||New_Email)
WHERE Email_Address LIKE V_OldDomain;
Fetch C_Domains into New_Email;
End Loop;
Close C_Domains;
End pr_update_email;
/
Show Errors;
getting errors:
19/11 PL/SQL: SQL Statement ignored
19/32 PLS-00403: expression'NEW_EMAIL' cannot be used as an INTO-target of a
SELECT/FETCH statement
You can directly update without creating a Stored Procedure but by using Regexp_Replace() and Instr() Functions :
SQL> Update Customer
Set Email_Address = Regexp_Replace(Email_Address,'(.*)#[gmail]+.(.*)','\1#hotmail.\2')
Where Instr(Email_Address,'#gmail.') > 0;
SQL> Commit;
If you want to create a generic structure in order to be able to use for such other cases also, then transfer the above Update statement as :
SQL> Create Or Replace Procedure pr_update_email(Old_Email Varchar2, New_Email Varchar2) As
Begin
Update Customer
Set Email_Address = Regexp_Replace(Email_Address,'(.*)#['||Old_Email||']+.(.*)','\1#'||New_Email||'.\2')
Where Instr(Email_Address,'#'||Old_Email||'.')>0 ;
End;
/
SQL> Begin
pr_update_email('gmail','hotmail');
End;
/
SQL> Commit;
Why you are using the cursor? It can be handled using simple update statement.
Your procedure should look like this:
create procedure pr_update_email (p_oldemail in varchar2,
p_newemail in varchar2)
As
Begin
UPDATE BROKER
SET
EMAIL_ADDRESS = REPLACE(EMAIL_ADDRESS, p_oldemail, p_newemail)
WHERE
REGEXP_LIKE ( EMAIL_ADDRESS,'.*#'|| p_oldemail|| '$' );
Commit;
End;
/
Or if you really want to use the loop then
create of replace procedure pr_update_email
(Old_Email Varchar2, New_Email Varchar2)
As
Begin
For i in (Select Email_Address
From Customer
where Email_Address Like '%#'||Old_Email) loop
Update Customer
Set Email_Address = Replace(Email_Address, old_email, new_email)
WHERE Email_Address = i.Email_Address;
End Loop;
Commit;
End pr_update_email;
/
To call this procedure, you need to pass both the domain as following:
Begin
pr_update_email('gmail.com', 'hotmail.com');
End;
/
And Yes, Issue in your code is following line:
Fetch C_Domains into New_Email;
New_Email is an input parameter and you can not assign any value to the input parameter.
Cheers!!
Write a procedure (oracle plsql) to do any one of the following: (a) update the table course and set the fee of the input course name equal to fee of java course. (b) insert a new row for given input course and set the fee lowest of all courses available in the table. Condition is: do (a) if the input course name is already present in the table otherwise do (b) if the input course name is not in the table.
I am providing here the basic details of table:
create table course(cid number primary key, cname varchar2(100), duration number, fee number);
insert into course (CID, CNAME, DURATION, FEE)
values (101, 'java', 30, 13000);
insert into course (CID, CNAME, DURATION, FEE)
values (102, 'c', 20, 5000);
insert into course (CID, CNAME, DURATION, FEE)
values (104, 'oracle', 20, 20000);
insert into course (CID, CNAME, DURATION, FEE)
values (105, 'python', 20, 30000);
insert into course (CID, CNAME, DURATION, FEE)
values (106, 'sql', 20, 1000);
I tried the below code but i don't know how to compare the given name for each rows in the table inside IF statement. Please take a look in the code and help me.
create or replace procedure proc_CourseFeeUpdateTry(coursename in course.cname%type,
java_fee out number) is
n_fee number;
j_fee number;
begin
if course.cname = coursename then --i'm getting error here
select t.fee into j_fee from course t where t.cname = 'java';
java_fee := j_fee;
update course t set t.fee = java_fee where t.cname = coursename;
dbms_output.put_line('new course added');
else
dbms_output.put_line(sqlerrm || '-' || sqlcode);
select min(t.fee) into n_fee from course t;
java_fee := n_fee;
insert into course values (103, coursename, 40, java_fee);
end if;
commit;
end;
The error you get seems to flow from a major misconception of available table data to procedure. An IF statement has no problem allowing subsequent selects. The problem here is you referenced a table column (course.cname) without having previously select anything from the course table. Just because a table exists does not give access to the data within it, you must select before referencing column values. So before that IF at you need at least a select and since it's a procedure a Select .. into specifically.
Now a select into makes column values available if it exist but if not it throws NO_DATA_FOUND exception. We this fact to avoid that IF entirely. Further there are 2 instances where you use the structure:
select data_value into local variable;
output_variable = local_variable;
This is not necessary as you can just select directly into the output_variable.
The following contains 2 revisions to your procedure. The 1st leaving your code as is as much as possible. The 2nd revising the code to make use of all the above mentioned. I hope this helps you understand further.
The minimum necessary change requires you to select the course table prior to your IF statement and handle the no_data_found_error.
create or replace procedure proc_CourseFeeUpdateTry(coursename in course.cname%type,
java_fee out number) is
n_fee number;
j_fee number;
l_course_name course.cname%type;
begin
begin
select c.cname
into l_course_name
from course c
where c.cname = coursename;
exception
when no_data_found then
null;
end ;
if l_course_name = coursename then
select t.fee into j_fee from course t where t.cname = 'java';
java_fee := j_fee;
update course t set t.fee = java_fee where t.cname = coursename;
dbms_output.put_line('course fee updated'); --- course was not added just updted
else
dbms_output.put_line(sqlerrm || '-' || sqlcode);
select min(t.fee) into n_fee from course t;
java_fee := n_fee;
insert into course values (103, coursename, 40, java_fee); --- leave message
dbms_output.put_line('new course added');
end if;
commit;
end;
The second version uses the above mentions topics and restructures.
create or replace procedure proc_CourseFeeUpdateTry(coursename in course.cname%type,
java_fee out number) is
l_cid course.cid%type;
begin
select c.cid
into l_cid
from course c
where c.cname = coursename;
begin -- inner block to trap java not found
-- if we get here then we know that the implied test cource.cname = coursename is true
select t.fee into java_fee
from course t where t.cname = 'java';
update course t set t.fee = java_fee where cid = l_cid;
dbms_output.put_line( coursename || ' fee updated');
commit;
exception
when no_data_found then
raise_application_error( -20109, 'course name ''java'' is not in course table');
end ; -- inner block
exception
when no_data_found then
-- if we get here the we know that the course name does not exist
select min(t.fee) into java_fee from course t;
insert into course values (103, coursename, 40, java_fee);
commit;
end;
Notice the insert in both procedures. It hard codes id. As a result your procedure is able to add a row exactly 1 time. This is an extremely poor process. Either pass the new id as a parameter (still not good, but better), or redefine the table to auto generate the key. Depending on your version of Oracle look up sequences and insert triggers (prior to 12c) or Identity Columns (12c and later).
I have a table 'Person' with columns as 'Person_id as primary key','DOB' and 'place' as follows:
'Person'
Person_id |Name|DOB | place
Another table is "employee" where emp_id is primary key as follows:
'employee'
Person_id |emp_id|dateofjoin
And one more table "Details":
'Details'
emp_id|competency|rating
Now what i want is once i add the 'Person' table details the rest of the two tables as'employe' and 'Details' to get updated also with respect to the new Person added in the Person table. So, how can i have this using sql query? Also i want to clear that i am not very much familiar with database.
I think your after something like this ( for SQL Server ):
Create Procedure dbo.CreateMyEmployee ( #empName varchar(50),
#dob datetime,
#doj datetime,
#place as varchar(100),
#competency varchar(100),
#rating int)
As
Begin
Declare #empId int
Begin Transaction
Begin Try
Insert into Person (Name, DOB, Place)
Values ( #empName, #dob, #place)
Insert into employe (Name, dateofJoin) -- Assuming emp_id is identity columen
Values ( #empName, #doj)
Select #empId = SCOPE_IDENTITY()
Insert Into Details(emp_id, competency, rating)
Values (#empId, #competency, #rating)
Commit transaction
End Try
Begin Catch
Rollback Transaction
SELECT ERROR_NUMBER() AS ErrorNumber, ERROR_MESSAGE() AS ErrorMessage
End Catch
End