The task is to get the maximum salary for employees holding the same position from a department. The position and department number are parameters of the function. here is the code
CREATE OR REPLACE FUNCTION getMaxSalary
(jobId in employees.job_id%TYPE,
dep_id in employees.department_id%TYPE
)
RETURN NUMBER IS
result NUMBER := 0;
BEGIN
SELECT MAX(salary)INTO result
FROM employees
WHERE job_id = jobId AND department_id = dep_id;
IF result IS NULL THEN
RAISE_APPLICATION_ERROR(-20201, 'This is not a valid department');
END IF;
RETURN result;
END;
ACCEPT x CHAR PROMPT 'Please enter Job ID:'
DECLARE
jobId employees.job_id%TYPE;
maxSalary NUMBER;
BEGIN
jobId:= '&x';
maxSalary:= getMaxSalary(jobId);
DBMS_OUTPUT.PUT_LINE('The max salary for job id: '|| maxSalary);
END;
ACCEPT works in SQL*Plus. You tagged the question with plsqldevelper tag which is related to Allround Automations GUI tool. What do you really use?
Anyway: try to add a slash to terminate PL/SQL block, here:
...
RETURN result;
END;
/ --> here
ACCEPT x CHAR PROMPT 'Please enter Job ID:'
DECLARE
...
Related
the question:
Write a blocK PL/SQL that display the total commission amount of a job id. Use function “compute_commission” that accepts a job id equal to 9 and return his total commission of all corresponding employees.
the error:
`Error at line 11: PLS-00103: Encountered the symbol "DECLARE"
CREATE OR REPLACE FUNCTION compute_commission (C_employee_id in number)
RETURN number
is `
the code:
CREATE OR REPLACE FUNCTION compute_commission (C_employee_id in number)
RETURN number
is
sum_commission number;
begin
select sum(job_id)
into sum_commission from employees
where employee_ref_id = C_employee_id;
return sum_commission;
end compute_commission;
declare
cal_sum_commission number;
begin
cal_sum_commission = compute_commission(cal_sum_commission);
dbms_output.put_line ('employee commission is: ' || compute_commission(cal_sum_commission);
end;
Should be something like this:
CREATE OR REPLACE FUNCTION compute_commission (C_employee_id IN NUMBER)
RETURN NUMBER
IS
sum_commission NUMBER;
BEGIN
SELECT SUM (job_id)
INTO sum_commission
FROM employees
WHERE employee_ref_id = C_employee_id;
RETURN sum_commission;
END compute_commission;
/
DECLARE
cal_sum_commission NUMBER := 12345;
BEGIN
cal_sum_commission := compute_commission (cal_sum_commission);
DBMS_OUTPUT.put_line (
'employee commission is: ' || cal_sum_commission);
END;
/
Note that I modified anonymous PL/SQL block and
added local variable's value (otherwise you'd pass NULL to the function) (you'll, of course, use some valid value; this - 12345 - is just an example)
used local variable in DBMS_OUTPUT.PUT_LINE
terminated statement with a semi-colon (you've had a colon)
fixed assignment operator (:= instead of just =)
Also, is sum_commision really sum of JOB_ID values? Looks strange to me ...
I'm trying to write a function invoiceCheck with one input parameter (invoice number) to check if the invoice exists in my database.
Create or replace function invoiceCheck(invoice_number_text IN
char)
RETURN char IS
invoice_id_text invoices.invoice_id%type;
invoice_total_text invoices.invoice_total%type;
invoice_due_date_text invoices.invoice_due_date%type;
BEGIN
select invoice_total
into invoice_total_text
from invoices
where invoices.invoice_number=invoice_number_text ;
return invoice_total_text;
END;
I also wrote a procedure InvoiceDetail that has one input parameter (invoice number). In the procedure, I called the function invoiceCheck to check if the invoice exists and if yes I want to display the invoice_id, invoice_total and invoice_due_date for that invoice. If not, I want to print out a message “invoice not in the database” from my procedure. Here is my procedure:
Create or replace procedure InvoiceDetail(invoice_number_text IN
char) IS
exist_invoice_number char;
invoice_total_text invoices.invoice_total%type;
invoice_id_text invoices.invoice_id%type;
invoice_due_date_text invoices.invoice_due_date%type;
BEGIN
select count(*) into exist_invoice_number from invoices
where invoices.invoice_id = invoice_id_text;
if exist_invoice_number is not null then
invoice_id_text := invoiceCheck(invoice_number_text);
invoice_total_text := invoiceCheck(invoice_number_text);
invoice_due_date_text := invoiceCheck(invoice_number_text);
dbms_output.put_line('Invoice ID:' ||invoice_id_text);
dbms_output.put_line('Invoice Total:' ||invoice_total_text);
dbms_output.put_line ( 'Invoice Due Date:' || invoice_due_date_text);
else
dbms_output.put_line('Invoice not in the database');
end if;
END;
When I go to execute an invoice number-QP58872 using:
set SERVEROUTPUT ON;
execute InvoiceDetail('QP58872');
I'm getting this error
ORA-01861: literal does not match format string
When I execute the function I get that the expression is of the wrong type but I don't know why. The return type that I use in the function is the same as where I try to put it in after the function is executed.
Below you find the record and table type.
TYPE department_id_table_type IS TABLE of DEPARTMENTS.DEPARTMENT_ID%TYPE;
TYPE managers_rec_type IS RECORD (
employee_id employees.employee_id%TYPE,
first_name employees.first_name%TYPE,
last_name employees.last_name%TYPE,
department_id_table_type DEPARTMENTS.DEPARTMENT_ID%TYPE);
TYPE managers_table_type IS TABLE OF managers_rec_type INDEX BY BINARY_INTEGER;
Below you find the function
FUNCTION managers_multiple_departments RETURN managers_table_type
IS
cursor department_curs is SELECT DEPARTMENT_NAME,MANAGER_ID,DEPARTMENT_ID FROM DEPARTMENTS WHERE MANAGER_ID IN (SELECT MANAGER_ID FROM DEPARTMENTS dep GROUP BY (MANAGER_ID) HAVING COUNT(MANAGER_ID) >1);
department_name departments.department_name%TYPE;
department_id departments.department_id%TYPE;
managerid departments.manager_id%TYPE;
employeeid employees.employee_id%TYPE;
firstname employees.first_name%TYPE;
lastname employees.last_name%TYPE;
count NUMBER;
rec managers_rec_type;
managers_rec managers_rec_type;
teller NUMBER := 1;
managers_table managers_table_type;
BEGIN
OPEN department_curs;
LOOP
FETCH department_curs INTO department_name, managerid,department_id;
EXIT WHEN department_curs%NOTFOUND;
Select EMPLOYEE_ID,FIRST_NAME,LAST_NAME,department_id into managers_rec from EMPLOYEES where MANAGER_ID = managerid;
managers_table(managers_rec.employee_id) := managers_rec;
FOR i IN managers_table.FIRST .. managers_table.LAST LOOP
IF managers_table.EXISTS(i) THEN
DBMS_OUTPUT.PUT_LINE(managers_table(i).first_name);
END IF;
END LOOP;
IF teller = 1 THEN
DBMS_OUTPUT.PUT_LINE(managers_rec.first_name ||' '|| managers_rec.last_name || ' Lijst van departments:');
teller := 2;
END IF;
DBMS_OUTPUT.PUT_LINE(department_id ||' '|| department_name);
END LOOP;
FOR i IN managers_table.FIRST .. managers_table.LAST LOOP
IF managers_table.EXISTS(i) THEN
DBMS_OUTPUT.PUT_LINE(managers_table(i).first_name);
DBMS_OUTPUT.PUT_LINE('test');
END IF;
END LOOP;
return managers_table;
END managers_multiple_departments;`enter code here`
Below is where I execute the function but this is where it is giving me the error on: managers := hr_package.managers_multiple_departments;
DECLARE
TYPE managers_rec_type IS RECORD (
employee_id employees.employee_id%TYPE,
first_name employees.first_name%TYPE,
last_name employees.last_name%TYPE,
department_id_table_type DEPARTMENTS.DEPARTMENT_ID%TYPE);
TYPE managers_table_type IS TABLE OF managers_rec_type INDEX BY BINARY_INTEGER;
man_rec managers_rec_type;
managers managers_table_type;
twee NUMBER;
BEGIN
managers := hr_package.managers_multiple_departments;
END;
You are declaring the record type, collection/table type and function all within the same package.
When you call the function you have to use the same type, from that package.
The return type that I use in the function is the same as where I try to put it in after the function is executed.
But it isn't. It has the same structure - fields and datatypes - but is not the same as far as Oracle is concerned. Oracle needs to know that exactly the same type is being used, partly so that it can keep track of dependencies between objects.
Your anonymous block needs to refer to the package types, rather than declaring its own - similar but conflicting - type(s):
DECLARE
managers hr_package.managers_table_type;
BEGIN
managers := hr_package.managers_multiple_departments;
END;
As a bonus it involves much less typing, and means you don't have to manage duplicate types.
It does also mean, though, that the type declarations have to be in the package specification - which is the case for anything you want to be publicly visible, of course.
I want to complete a task that says:
Search in the user given table, in the user given column the user given value using explicite cursor. This means I have to use the & operator to input the table name, column name and value. If I found the given object, give a varchar found else not found. How to input the table name, column name and the value (that is of correct type of course)?
I tried it but failed miserably:
declare
#Mytable varchar2;
#Mycolumn varchar2;
Myvalue #Mycolumn%TYPE;
oneLine #Mytable%ROWTYPE;
found varchar2;
cursor kurzor is select * from #Mytable;
begin
open kurzor;
loop
fetch kurzor into oneLine;
if oneLine.#Mycolumn = Myvalue then
found='found';
end if;
exit when kurzor%NOTFOUND;
end loop;
close kurzor;
end;
/
You don't need to describe variables for table name, column name and etc. in section DECLARE. Just use substitution variables.
DECLARE
CURSOR cur IS SELECT &myColumn FROM &myTable;
currentVal VARCHAR2(4000);
isFound VARCHAR2(10):= 'not found';
BEGIN
OPEN cur;
LOOP
FETCH cur INTO currentVal;
EXIT WHEN cur%NOTFOUND;
IF currentVal = &myValue THEN
isFound:= 'found';
EXIT;
END IF;
END LOOP;
CLOSE cur;
dbms_output.put_line(isFound);
END;
Please see my code below. If the parameter p_cust_id is not in the column cust_id I want "0" to be printed out (which means not logged in). If it is in cust_id I want oracle to continue the second part of the code (the part below the empty row).
I have tried to solve this by inserting the values of column cust_id in a cursor and then inserting it in the variable v_cust_id. Perhaps this results in unnecessarily much code?
My problem is that the program does not seem to run the second part even if p_cust_id is in cust_id. It just prints out "0" even though the customer ID and the password are correct.
Before I added the cursor the program worked as it was supposed to, unless the parameter p_cust_id didn't match any value in the cust_id column. If this was the case nothing was printed out.
create or replace function log_in(
p_cust_id in customer.cust_id%type,
p_passwd in customer.passwd%type)
return varchar2
as
cursor c_cust_id is select cust_id from customer;
v_cust_id customer.cust_id%type;
v_passwd customer.passwd%type;
v_logged_in number(1);
v_not_logged_in number(1);
begin
v_logged_in := 1;
v_not_logged_in := 0;
if not c_cust_id%isopen then
open c_cust_id;
end if;
loop
fetch c_cust_id
into v_cust_id;
exit when c_cust_id%notfound;
end loop;
if p_cust_id not in(v_cust_id) then
return v_not_logged_in;
end if;
close c_cust_id;
select passwd
into v_passwd
from customer
where cust_id = p_cust_id;
if v_passwd = p_passwd then
return v_logged_in;
else
return v_not_logged_in;
end if;
end;
I could see, you don't need a cursor at all, to check if the cust_id is in the table. Just search for the cust_id in the table, and attempt to fetch the password. If it exists, you get the value, and NO_DATA_FOUND exception otherwise which means not logged in.
BEGIN
select passwd
into v_passwd
from customer
where cust_id = p_cust_id;
EXCEPTION
WHEN NO_DATA_FOUND THEN
return v_not_logged_in;
END;
Full code will be:
create or replace function log_in(
p_cust_id in customer.cust_id%type,
p_passwd in customer.passwd%type)
return varchar2
as
v_cust_id customer.cust_id%type;
v_passwd customer.passwd%type;
v_logged_in number(1);
v_not_logged_in number(1);
begin
v_logged_in := 1;
v_not_logged_in := 0;
BEGIN
select passwd
into v_passwd
from customer
where cust_id = p_cust_id;
EXCEPTION
WHEN NO_DATA_FOUND THEN
return v_not_logged_in;
END;
if v_passwd = p_passwd then
return v_logged_in;
else
return v_not_logged_in;
end if;
end;