PL/SQL Loop issue with Cursor - oracle

I am trying to create a PL/SQL script that selects the last name and salary of an employee from the table employees. I have a cursor that stores the data and I fetch the cursor which then inserts the data into a new table called BIG_MONEY. I have a user input that selects the number of employees the loop will run through and the loop ends when it reaches the figure they provided.
SET SERVEROUTPUT ON
DROP TABLE BIG_MONEY;
ACCEPT NumberOfStaff
CREATE TABLE BIG_MONEY (
last_name VARCHAR2(10),
salary NUMBER(7, 2)
);
DECLARE V_EMP_ID employees.employee_id%TYPE;
V_EMP_LASTNAME employees.last_name%TYPE;
V_EMP_SALARY employees.salary%TYPE;
CURSOR EMP_Cursor IS
SELECT employee_id, last_name, salary
FROM employees
ORDER BY salary DESC last_name ASC
BEGIN
OPEN EMP_Cursor;
LOOP
FETCH EMP_Cursor INTO V_EMP_ID, V_EMP_LASTNAME, V_EMP_SALARY;
INSERT INTO BIG_MONEY (last_name, salary)
VALUES (V_EMP_LASTNAME, V_EMP_SALARY)
EXIT WHEN EMP_Cursor%ROWCOUNT = '&NumberOfStaff';
DMBS_OUTPUT.PUT_LINE
('Employee' || TO_CHAR (V_EMP_ID) || 'last name is' || TO_CHAR (V_EMP_LASTNAME)
|| 'and makes' || TO_CHAR (V_EMP_SALARY) || 'a month');
END LOOP;
CLOSE EMP_Cursor;
What am I doing wrong here? I would assume my logic is correct but the syntax is where I'm making a mistake.

Related

ORA-01007: variable not in select list-1007

I have the table below:
CREATE TABLE req1_tb(TableName VARCHAR2(43),
ColumnName VARCHAR2(98),
Edit_ind CHAR)
Here's the dml for this table:
insert into req1_tb VALUES('Employees','employee_id','Y');
insert into req1_tb VALUES('Employees','first_name','Y');
insert into req1_tb VALUES('Employees','last_name','N');
insert into req1_tb VALUES('Employees','email','N');
insert into req1_tb VALUES('Employees','job_id','N');
insert into req1_tb VALUES('Employees','salary','Y');
insert into req1_tb VALUES('Employees','commission_pct','Y');
insert into req1_tb VALUES('Employees','hire_date','N');
insert into req1_tb VALUES('Employees','department_id','Y');
I assumed that edit_ind column in enter code here below table will change dynamically
SQL> SELECT * FROM REQ1_TB;
TABLENAME COLUMNNAME EDIT_IND
------------------------------------------- --------------- ----------
Employees employee_id Y
Employees first_name Y
Employees last_name N
Employees email N
Employees job_id N
Employees salary Y
Employees commission_pct Y
Employees hire_date N
Employees department_id Y
I have created procedure that will dynamically print columns who are marked 'Y' only:
CREATE OR REPLACE PROCEDURE dyn_sql_sp
AS
cols VARCHAR2(2000);
v_cols VARCHAR2(2000);
cls VARCHAR2(2000);
v_employee_id number;
emp employees%rowtype;
cnt number;
cursor tab_c
is
select columnname from req1_tb
where EDIT_IND='Y';
cursor col_c
is
select employee_id from employees;
BEGIN
for i in tab_C
loop
cols:=cols||'emp.'||i.columnname||',';
end loop;
cols:=rtrim(cols,',');
for i in col_c
loop
EXECUTE IMMEDIATE 'SELECT ' || cols || ' FROM employees WHERE employee_id = :1'
INTO emp
USING i.employee_id;
end loop;
dbms_output.put_line(cols);
Exception
When Others Then
dbms_output.put_line(sqlerrm||sqlcode);
end;
/
While executing I got the following error:
SQL> exec dyn_sql_sp;
ORA-01007: variable not in select list-1007
In your procedure the below code is going to create problem. As far i understand you are trying to select columns of table employee depending on 'Y' flag from table req1_tb.
Problematic Part:
for i in col_c
loop
EXECUTE IMMEDIATE 'SELECT ' || cols || ' FROM employees WHERE employee_id = :1'
--***The INTO clause is problematic here. Since the you select list is not*** having all the columns same as your cursor variable.
INTO emp
USING i.employee_id;
end loop;
Now, you are not trying the same logic while declaring a variable to hold the data returned from those selected columns in Execute Immediate statement.
For that the variable declaration should also be dynamic. So you declaration
emp employees%rowtype;
should be such that it also have all the selected columns satisfying condition flag 'Y'. You cannot insert few columns selected from your select statement to a cursor variable having all the columns.

PL/SQL inserting a new record exception handling

I have an assignment in Oracle PL/SQL. I have to count the maximum number of employees working under a manager, and if this manager has more than 7 employees working under him I must raise an exception, which gives the message:
('Manager ||manager_name||' has maximium number of employees working under him'.)
Otherwise I must insert a new employee and give the message:
('It was inserted a new employee for the manager ||manager_name).
I have written the code, but I know something is wrong.
create table temp_emp as select * from employees;
select * from temp_emp;
create or replace procedure insert_emp(mngrId IN temp_emp.manager_id%type)
IS
ex_hugemp EXCEPTION;
emp_counter NUMBER;
fname temp_emp.first_name%type;
BEGIN
SELECT COUNT(*) INTO emp_counter
FROM temp_emp
WHERE temp_emp.manager_id=mngrId;
IF emp_counter > 7 THEN
RAISE ex_hugemp;
ELSE
INSERT INTO temp_emp(EMPLOYEE_ID, FIRST_NAME, LAST_NAME, EMAIL, PHONE_NUMBER
,HIRE_DATE, JOB_ID, SALARY, COMMISSION_PCT
,MANAGER_ID,DEPARTMENT_ID)
VALUES(LENGTH(EMPLOYEE_ID)+1, 'KAY', 'HORSTMAN', NULL, NULL
,'28-MAY-2013', 'IT_PROG', 24000, NULL, 103, 60);
DBMS_OUTPUT.PUT_LINE('It was inserted a new employee for the manager '||fname);
END IF;
EXCEPTION
WHEN ex_hugemp THEN
DBMS_OUTPUT.PUT_LINE('Manager '||fname||' has maximium number of employees working under him.');
END;
/
Your variable fname is empty. Fill it:
SELECT first_name
INTO fname
FROM temp_emp
WHERE employee_id = mngrid;
Use for the insert the same mngrid. Why is 103?
What is
LENGTH(EMPLOYEE_ID)+1
First: this will convert employee_id in string, get the length from the string and add 1. Do you really want this?. And second: you cannot use column name in values(). Create sequence (change 1 with your value to start):
CREATE SEQUENCE TEMP_EMP_SEQ START WITH 1;
and than use it in your procedure
temp_emp_seq.nextval
.
CREATE OR REPLACE PROCEDURE insert_emp (mngrid IN temp_emp.manager_id%TYPE) IS
ex_hugemp EXCEPTION;
emp_counter NUMBER;
fname temp_emp.first_name%TYPE;
BEGIN
SELECT first_name
INTO fname
FROM temp_emp
WHERE employee_id = mngrid;
SELECT COUNT (*)
INTO emp_counter
FROM temp_emp
WHERE temp_emp.manager_id = mngrid;
IF emp_counter > 7 THEN
RAISE ex_hugemp;
ELSE
INSERT INTO temp_emp (employee_id, first_name, last_name, email, phone_number, hire_date, job_id, SALARY,COMMISSION_PCT,MANAGER_ID,DEPARTMENT_ID)
VALUES( temp_emp_seq.nextval,'KAY','HORSTMAN',NULL,NULL,TO_DATE('28-05-2013','dd-mm-yyyy'),'IT_PROG',24000,NULL,mngrid,10);
DBMS_OUTPUT.put_line ('It was inserted a new employee for the manager ' || fname);
END IF;
EXCEPTION
WHEN ex_hugemp THEN
DBMS_OUTPUT.put_line ('Manager ' || fname || ' has maximium number of employees working under him.');
END;
/

cannot reference to cursor instances oracle pl/sql

CREATE OR REPLACE PROCEDURE employee_info_all_in_one
(p_id IN NUMBER)
IS
CURSOR c_city IS
(SELECT l.city
FROM employees e
INNER JOIN departments d
ON (e.department_id = d.department_id)
INNER JOIN locations l
ON (l.location_id = d.location_id)
WHERE e.employee_id = p_id);
CURSOR c_manager IS
(SELECT e1.last_name
FROM employees e1
INNER JOIN
employees e2
ON (e1.employee_id = e2.manager_id)
WHERE e2.employee_id = p_id);
CURSOR c_department_name IS
(SELECT department_name
FROM employees e
INNER JOIN
departments d
ON (e.department_id = d.department_id)
WHERE e.employee_id = p_id);
TYPE EmpRecTyp IS RECORD
( v_annual_sal NUMBER(9,2),
v_monthly_sal NUMBER(9,2),
v_last_name VARCHAR2(10),
v_deptno NUMBER(3),
v_length NUMBER(2),
v_tenure NUMBER(5),
v_job_id VARCHAR2(20),
v_hire_date DATE,
v_city VARCHAR(25),
v_commission_pct NUMBER(2,2),
v_phone_number VARCHAR2(20),
v_manager VARCHAR2(20),
v_comm_calc NUMBER(10,2),
v_email VARCHAR2(10),
v_department VARCHAR2(20),
v_count NUMBER(4)
);
TYPE EmpRecTyp IS REF CURSOR;
emp_c_v EmpRecTyp;
BEGIN
DBMS_OUTPUT.PUT_LINE('Welcome to the summary of an employee based on his unique id');
DBMS_OUTPUT.PUT_LINE('============================================================');
SELECT salary, last_name, department_id,
TRUNC(MONTHS_BETWEEN(SYSDATE,hire_date),0), job_id,
hire_date, commission_pct, phone_number, email
INTO emp_c_v.v_monthly_sal, emp_c_v.v_last_name, emp_c_v.v_deptno,
emp_c_v.v_tenure, emp_c_v.v_job_id, emp_c_v.v_hire_date, emp_c_v.v_commission_pct,
emp_c_v.v_phone_number, emp_c_v.v_email
FROM employees
WHERE employee_id = p_id;
emp_c_v.v_count := SQL%ROWCOUNT;
DBMS_OUTPUT.PUT_LINE(emp_c_v.v_count||' row retrieved...');
DBMS_OUTPUT.PUT_LINE('=============================');
emp_c_v.v_annual_sal := emp_c_v.v_monthly_sal * 12;
emp_c_v.v_length := LENGTH(emp_c_v.v_last_name);
DBMS_OUTPUT.PUT_LINE('Employee:-> ' || emp_c_v.v_last_name || ' ,and his name contains: ' || emp_c_v.v_length ||' chars');
DBMS_OUTPUT.PUT_LINE('=============================');
DBMS_OUTPUT.PUT_LINE(q'[Belong's to department: ]' || emp_c_v.v_deptno);
DBMS_OUTPUT.PUT_LINE('=============================');
IF (emp_c_v.v_monthly_sal < emp_c_v.v_annual_sal)
THEN
DBMS_OUTPUT.PUT_LINE('Has a annual salary of:-> ' || emp_c_v.v_annual_sal);
ELSE
DBMS_OUTPUT.PUT_LINE('Something wrong in the formula!');
END IF;
IF emp_c_v.v_commission_pct IS NULL
THEN
DBMS_OUTPUT.PUT_LINE('No Commission added to the annual salary!');
ELSE
DBMS_OUTPUT.PUT_LINE('Commission percentage to the salary is:-> '|| emp_c_v.v_commission_pct ||'%');
emp_c_v.v_comm_calc := (emp_c_v.v_annual_sal * emp_c_v.v_commission_pct) + emp_c_v.v_annual_sal;
DBMS_OUTPUT.PUT_LINE('And calculated with annual salary is:->' ||v_comm_calc);
END IF;
DBMS_OUTPUT.PUT_LINE('Working for:-> '|| emp_c_v.v_tenure || ' months as '|| emp_c_v.v_job_id);
DBMS_OUTPUT.PUT_LINE('=============================');
DBMS_OUTPUT.PUT_LINE('Started in:-> '|| emp_c_v.v_hire_date);
DBMS_OUTPUT.PUT_LINE('=============================');
DBMS_OUTPUT.PUT_LINE('Phone number:-> '||emp_c_v.v_phone_number);
DBMS_OUTPUT.PUT_LINE('=============================');
DBMS_OUTPUT.PUT_LINE('Email:-> '||emp_c_v.v_email);
DBMS_OUTPUT.PUT_LINE('=============================');
OPEN c_city;
FETCH c_city INTO v_city;
IF c_city%FOUND
THEN
DBMS_OUTPUT.PUT_LINE('Location:-> '||emp_c_v.v_city);
ELSE
DBMS_OUTPUT.PUT_LINE('Employee location unknown');
END IF;
CLOSE c_city;
OPEN c_manager;
FETCH c_manager INTO emp_c_v.v_manager;
IF c_manager%FOUND
THEN
DBMS_OUTPUT.PUT_LINE('Is in the eyes of manager:-> '||emp_c_v.v_manager);
ELSE
DBMS_OUTPUT.PUT_LINE('Slave '||emp_c_v.v_last_name||' is free!');
END IF;
CLOSE c_manager;
OPEN c_department_name;
FETCH c_department_name INTO emp_c_v.v_department;
IF c_department_name%FOUND
THEN
DBMS_OUTPUT.PUT_LINE('Department Name:-> '||emp_c_v.v_department);
ELSE
DBMS_OUTPUT.PUT_LINE('Employee ' ||emp_c_v.v_last_name||' belongs to no department!');
END IF;
DBMS_OUTPUT.PUT_LINE('================================');
DBMS_OUTPUT.PUT_LINE('Checking for employee with id '|| p_id ||'..');
IF (check_sal2(p_id) IS NULL)
THEN
DBMS_OUTPUT.PUT_LINE('The function returned NULL due to exception, therefore employee does not exist!');
ELSIF (check_sal2(p_id))
THEN
DBMS_OUTPUT.PUT_LINE('Employees salary > average of department '||emp_c_v.v_deptno||' where he belongs.');
ELSE
DBMS_OUTPUT.PUT_LINE('Salary < average of department '||emp_c_v.v_deptno||', where he belongs.');
END IF;
DBMS_OUTPUT.PUT_LINE('=====================================================');
END;
Initially i had only simple variables (v_...) declared in this sub-program but i wanted to make use of true cursor variables i.e like-pointers? i suppose. So i modified and defined a type of record and referenced a cursor "...IS REF CURSOR" for the variables or fields inside it. But when i compile this whole thing i get the error of invalid reference to variable "emp_c_v", why? I am still in the learning stages so sorry for talking nonsense. Thanks
A cursor is a pointer to a result set (sort of), not to an individual record. You can't ever modify a result set. In this case the pointer wouldn't actually point to anything as there isn't a result set (from a query) for it to point to.
Your code will almost compile if you drop the ref cursor and make your variable a record type; so instead of:
TYPE EmpCurTyp IS REF CURSOR;
emp_c_v EmpCurTyp;
use:
emp_c_v EmpRecTyp;
You've also missed a couple of places when changing your references:
DBMS_OUTPUT.PUT_LINE('And calculated with annual salary is:->' ||v_comm_calc);
and
FETCH c_city INTO v_city;
... both need the emp_c_v. prefix before v_comm_calc and v_city respectively.
I assume you're using this as a learning exercise, otherwise this could all be done much more simply.

Oracle PL/SQL using cursor with for loop for data retrieving

Hi I am trying to use for loop for retrieving data in oracle pl/sql but I am getting an error can someone help me
SET SERVEROUTPUT ON
DECLARE
fname employees.first_name%TYPE;
empid employees.employee_id%TYPE;
CURSOR emp_cursor IS
SELECT employee_id,first_name from employees ORDER BY employee_id;
BEGIN
open emp_cursor;
FOR empid IN emp_cursor loop
DBMS_OUTPUT.PUT_LINE('employee id is ' ||empid || 'first name is '||fname);
end LOOP;
END;
I am getting an error on the DBMS output line something like the number or type of variables not right. I am trying to retrieve employee id and first name from employees table in oracle sample schema.
Can someone please guide me
USING FOR..LOOP in CURSORS.
SET SERVEROUTPUT ON
DECLARE
/* DECLARE Cursor */
CURSOR emp_cursor IS
SELECT employee_id,first_name from employees ORDER BY employee_id;
BEGIN
FOR empid IN emp_cursor loop
/* empid already has the row details, you don't need to have any other variables */
DBMS_OUTPUT.PUT_LINE('employee id is ' ||empid.employee_id || 'first name is '||empid.first_name);
end LOOP;
END;
/
USING OPEN FETCH and CLOSE
SET SERVEROUTPUT ON
DECLARE
fname employees.first_name%TYPE;
empid employees.employee_id%TYPE;
CURSOR emp_cursor IS
SELECT employee_id,first_name from employees ORDER BY employee_id;
BEGIN
open emp_cursor;
/* LOOP until the cursor is empty */
LOOP
FETCH emp_cursor INTO empid,fname;
/* Now we fetch data from cursor, and put it into our variables */
EXIT WHEN emp_cursor%NOTFOUND;
DBMS_OUTPUT.PUT_LINE('employee id is ' ||empid || 'first name is '||fname);
END LOOP;
/* As we OPEN'ed the cursor manually, we have to CLOSE it without fail */
CLOSE emp_cursor;
END;
/

Display columns for 4 employee have job id like SA_MAN and have salary >10000

I want to display: employee id, employee name, job id, salary, for 4 employee have job id like SA_MAN and have salary >10000 using loop statements I wrote this code but I get an error
What's wrong with this code?
DECLARE
emp_name employees.last_name%type;
emp_id employees.employee_id%type;
sal employees.salary%type;
jobid employees.job_id%type;
BEGIN
SELECT employee_id,
last_name,
job_id,
salary
INTO emp_id,
emp_name,
jobid,
sal
FROM employees
WHERE salary>10000
AND job_id LIKE'%SA\_%N' ESCAPE'\';
FOR i 1..3 dpms_output.put_line(emp_id||' '||emp_name||' '||jobid||' '||sal);
END LOOP;
END;
This is the error I get:
Error starting at line 1 in command:
DECLARE
emp_name employees.last_name%type;
emp_id employees.employee_id%type;
sal employees.salary%type;
jobid employees.job_id%type;
BEGIN
SELECT employee_id,
last_name,
job_id,
salary
INTO emp_id,
emp_name,
jobid,
sal
FROM employees
WHERE salary>10000
AND job_id LIKE'%SA\_%N' ESCAPE'\';
FOR i 1..3 dpms_output.put_line(emp_id||' '||emp_name||' '||jobid||' '||sal);
END LOOP;
END;
Error report:
ORA-06550: line 20, column 7:
PLS-00103: Encountered the symbol "1" when expecting one of the following:
in
06550. 00000 - "line %s, column %s:\n%s"
*Cause: Usually a PL/SQL compilation error.
*Action:
This can be achieved by doing the following:
begin
for i in ( SELECT employee_id, last_name, job_id, salary
FROM employees
WHERE salary > 10000
AND job_id LIKE '%SA\_%N' ESCAPE '\' ) LOOP
dbms_output.put_line( i.employee_id || ' '
|| i.last_name || ' '
|| i.job_id || ' '
|| i.salary );
end loop;
end;
You don't need to do this though. You can just SELECT what you want. More generally, please pay attention to your spacing, it makes your code a lot more readable.
The actual errors are as follows:
If you're performing a FOR LOOP you need an IN and a LOOP
FOR i 1..3 should be for i in 1 .. 3 loop
dbms_output is spelt as I have done, not dpms_output.
You're selecting multiple rows into a type defined as a single row. This will raise the TOO_MANY_ROWS exception. Equally, if this query returned 0 rows a NO_DATA_FOUND exception will be raised.
If you want to select everything and then loop through the values you could use a BULK COLLECT. It's overkill though for this situation. Note that I don't assume the number of values that the query is going to return.
declare
cursor c_emp is
select employee_id, last_name, job_id, salary
from employees
where salary > 10000
and job_id like '%SA\_%N' ESCAPE '\';
type t__emp is table of c_emp%rowtype index by binary_integer;
t_emp t__emp;
begin
open c_emp;
fetch c_emp bulk collect into t_emp;
close c_emp;
for i in t_emp.first .. t_emp.last loop
dbms_output.put_line( i.employee_id || ' '
|| i.last_name || ' '
|| i.job_id || ' '
|| i.salary );
end loop;
end;
/
Apologies for the syntax highlighting. There's a bug with Google Prettify on escaped single quotes in the SQL markdown.

Resources