Procedure never raise NO_DATA_FOUND Exception - sql

i've created an procedure which increases salaries of peoples working in a department by a certain rate. the department number and the rate are assed as parameters for the procedure.
Now, the procedure works great when i specify the good departement number, but once i specify a false one, and i'm waiting for the NO_DATA_FOUND Exception to raise, it never happen. I searched tried many thing but didn't found the answer, so if you can help me i woul be really greatfull. Thank you !
Here is my code :
create or replace PROCEDURE AugmenteSalaire(numDepartement in departements.numerodepartement%TYPE, taux IN number) IS
p_nbreTotalSalaire employes.salaireemploye%type;
begin
SELECT sum(salaireemploye)
INTO p_nbreTotalSalaire
FROM employes
WHERE numerodepartement = numDepartement;
if taux > 0 AND taux <= 100 THEN
if p_nbreTotalSalaire < 150000 THEN
Update employes e
SET e.salaireemploye = e.salaireemploye + (e.salaireemploye * (taux * 0.01))
WHERE e.numerodepartement = numDepartement
AND NOT numeroemploye = (SELECT departements.chefdepartement from departements
WHERE departements.numerodepartement = numDepartement);
ELSE
DBMS_OUTPUT.PUT_LINE('Transaction refused : The salary sum cannot be above 150000');
END IF;
ELSE
DBMS_OUTPUT.PUT_LINE('The rate cannot be under 0 or aboce 100');
END IF;
Exception
WHEN NO_DATA_FOUND THEN
DBMS_OUTPUT.PUT_LINE('The department number provided is invalid, '||
'please enter a valid department number(DEP001 for example)');
end;

SELECT sum(salaireemploye)
INTO p_nbreTotalSalaire
FROM employes
WHERE numerodepartement = numDepartement;
In this query you are using SUM(). Now if there is no matching department, i.e. input "numDepartement" is a false department, sum(salaireemploye) is 0 (no such department, so nothing to add, so 0).
sum(salaireemploye) thus has a valid value, which is 0 here. Hence this will never raise a NO_DATA_FOUND exception

Related

Cause a job failure with sql for data checks

I would like to action some data checks following data imports into my system, im checking that all of my key locations have inventory imported for them and if they dont i would like the job to fail (I then have reporting/alerts set up when any jobs fail)
Ive had a search around and tried a number of options - The lines commented out are what i have tried but when i set INV_CHECK variable above the count level of one of my locations the job still completed succesfully. If i run in TOAD then it will fail and present an error which is what i had wanted the job to do.
Declare valid_loc NUMBER;
Inv_check NUMBER;
no_inv number;
BEGIN
select param_value into Inv_check from
scpomgr.udt_systemparam where param_name = 'INV_CHECK';
select count (*) into valid_loc from
(select distinct loc
from scpomgr.inventory
where loc in ('GB01', 'FR01', 'DE01', 'IT01', 'ES01', 'IE01', 'CN01', 'JP01', 'AU01', 'US01')
having count (*) > Inv_check
group by loc);
if valid_loc
<10 THEN
--raise_application_error(-20001,'Likely Missing Inv Records');
--raiseerror('fail',16,1);
--select 1/0 into no_inv from dual;
--THROW (51000, 'Process Is Not Finished', 1);
END IF;
END;
EXIT
Can anyone point me in the right direction of what ive missed / misunderstood?
Ive added an action into the If statement so i know its running the part after the 'Then' and if i run in TOAD it gives me an error, if i do it via 'PUTTY' which is what i use to run batch processes then it comes out as 'COMPLETE' and doesnt show any sort of failure.
So after a number of trial and error i found the below code gives me the desired result, to cause my process table / putty runs to display failed i needed to use pkg_job.fatel_error and with that i could pass an error message/code.
Declare
valid_loc NUMBER;
Inv_check NUMBER;
BEGIN
select param_value into Inv_check from
scpomgr.udt_systemparam where param_name = 'INV_CHECK';
select count (*) into valid_loc from
(select distinct loc
from scpomgr.inventory
where loc in ('GB01', 'FR01', 'DE01', 'IT01', 'ES01', 'IE01', 'CN01', 'JP01', 'AU01', 'US01')
group by loc
having count (*) > Inv_check
);
if valid_loc < 10 THEN
pkg_job.fatal_error('Likely Missing Inv Records',-20001);
END IF;
END;
/
EXIT
Hope this helps others or gives ideas of what to try.

SQL - hr database

I need to to select id, name and annual compensation.
I am running the script and everything is okay. I am asking to show me the result for id=100 and everything is perfect.
My problem is - if I want to check for id=300 (which is not in the table) I need to get result 'No employee with that ID' but it returns me 'no rows selected'. Is there something wrong with my last SELECT or with the EXCEPTION?
RETURN NUMBER IS
v_sal employees.salary%TYPE;
v_comm employees.commission_pct%TYPE;
BEGIN
SELECT salary,commission_pct INTO v_sal,v_comm
FROM employees
WHERE employee_id=v_empid;
RETURN (NVL(v_sal,0) * 12 + (NVL(v_comm,0) * NVL(v_sal,0) * 12));
EXCEPTION
WHEN NO_DATA_FOUND THEN
DBMS_OUTPUT.PUT_LINE('No employee with that ID');
END get_annual_emp;
SELECT employee_id,last_name,
get_annual_emp(employee_id) "Annual Compensation"
FROM employees
WHERE employee_id=&v_empid;
Looks like exception handler doesn't do its job as you presumed it will.
A function is supposed to return some value. You're just displaying a message (on the screen, using dbms_output.put_line - that's not visible elsewhere, in a tool that doesn't support it).
Therefore, you could return null:
EXCEPTION
WHEN NO_DATA_FOUND THEN
DBMS_OUTPUT.PUT_LINE('No employee with that ID');
RETURN null;
END get_annual_emp;
Or, raise an error:
EXCEPTION
WHEN NO_DATA_FOUND THEN
RAISE_APPLICATION_ERROR(-20000, 'No employee with that ID');
END get_annual_emp;
You can't actually return "No employee with that ID" as return value because it is a string, and your function returns a number. You could modify return value's datatype to varchar2, but - you do expect a number, don't you?

Looking at IF, WHERE, and WHEN in PL SQL

I am completing an academic assignment that asks to prompt the user for their target sales and their employee id. If the target sales exceeds or equates to that of the actual company sales for 2015, then raises can be applied.
I've composed a majority of code but I am stuck on the END IF; statements on line 25. I'm receiving error(s)
ORA-06550, PLS-00103: Encountered the symbol "WHERE" when expecting
one of the following.
I think I might be struggling to integrate the if statement that compares the user input to the company sales for 2015.
Insights greatly appreciated! Thank you!
accept emp_target prompt 'Please enter your company sales target: '
accept empno prompt 'Please enter your employee ID: '
DECLARE
emp_target NUMBER := &emp_target;
cmp_target NUMBER;
empno emp_employees.emp_id%type := &empno;
new_sal emp_employees.salary%type;
cnt number;
CURSOR sales_cur IS
SELECT SUM(oe_orderDetails.quoted_price)
FROM oe_orderDetails
JOIN oe_orderHeaders
ON oe_orderDetails.order_id = oe_orderHeaders.order_id
WHERE oe_orderHeaders.order_date >= to_date('1.1.' || 2015, 'DD.MM.YYYY')
and oe_orderHeaders.order_date < to_date('1.1.' || (2015 + 1), 'DD.MM.YYYY');
BEGIN
OPEN sales_cur;
FETCH sales_cur INTO cmp_target;
IF cmp_target >= emp_target THEN
UPDATE emp_employees SET
emp_employees.salary = case WHEN emp_employees.dept_id = 10 THEN emp_employees.salary * 1.1
WHEN emp_employees.emp_id = 145 THEN emp_employees.salary * 1.15
WHEN emp_employees.dept_id = 80 THEN emp_employees.salary * 1.2
ELSE emp_employees.salary
END IF;
END
WHERE emp_employees.emp_id = empno
returning emp_employees.salary into new_sal;
cnt := sql%rowcount;
IF cnt > 0 THEN
dbms_output.put_line('Employee ' || empno || ', new salary = ' || new_sal);
ELSE
dbms_output.put_line('Nobody got new salary');
END IF;
END;
/
The main issue is that you have misplaced the CASE block's end and where clause out after END IF.
Apart from that I would say that the cursor block was not required to store a simple SUM, but i'll let you use it since you are learning for an assignment.
The other problem after you fix the first one is your returning emp_employees.salary into new_sal. A scalar variable can't contain multiple rows returned from the dml which updates more than one row. You should use a collection(nested table) instead. Use RETURNING BULK COLLECT INTO to load it and loop over later to display your final message.
Please read all my code comments carefully. I cannot test the whole code for any errors as I have none of your tables. You should fix if there are any if you can or let us know if you can't.
ACCEPT emp_target PROMPT 'Please enter your company sales target: '
ACCEPT empno PROMPT 'Please enter your employee ID: '
DECLARE
emp_target NUMBER := &emp_target;
cmp_target NUMBER;
empno emp_employees.emp_id%TYPE := &empno;
TYPE sal_type IS
TABLE OF emp_employees.salary%TYPE; --nested table(collection) of salary
new_sal sal_type; -- a collection variable
cnt NUMBER;
CURSOR sales_cur IS SELECT SUM(oe_orderdetails.quoted_price)
FROM oe_orderdetails
JOIN oe_orderheaders ON oe_orderdetails.order_id = oe_orderheaders.order_id
WHERE oe_orderheaders.order_date >= TO_DATE('1.1.' || 2015,'DD.MM.YYYY') AND
oe_orderheaders.order_date < TO_DATE('1.1.' || (2015 + 1),'DD.MM.YYYY'); --is it required to specify (2015 + 1) instead of 2016?
BEGIN
OPEN sales_cur;
FETCH sales_cur INTO cmp_target;
IF
cmp_target >= emp_target
THEN
UPDATE emp_employees
SET
emp_employees.salary =
CASE
WHEN emp_employees.dept_id = 10 THEN emp_employees.salary * 1.1
WHEN emp_employees.emp_id = 145 THEN emp_employees.salary * 1.15
WHEN emp_employees.dept_id = 80 THEN emp_employees.salary * 1.2
ELSE emp_employees.salary
END
WHERE emp_employees.emp_id = empno --misplaced where and end
RETURNING emp_employees.salary BULK COLLECT INTO new_sal;
END IF;
cnt := new_sal.count; --no of records in nested table
IF
cnt > 0
THEN
FOR i IN new_sal.first..new_sal.last LOOP
dbms_output.put_line('Employee ' || empno || ', new salary = ' || new_sal(i) );
END LOOP;
ELSE
dbms_output.put_line('Nobody got new salary');
END IF;
CLOSE sales_cur; -- always remember to close the cursor
END;
/

Simple PL/SQL Code will not run. I cannot find the error

I've been tweaking and trying to debug this PL/SQL code for like 4 hours now. I have also tried to search on here but it is so specific that I really need help. Here is my code, When I try to run it, the two prompt questions pop up. After I answer the second one, oracle just stops running.
---- File PLh20.sql
-- Author: <<< NAME >>>
-------------------------------------------------------------------
SET SERVEROUTPUT ON
SET VERIFY OFF
------------------------------------
ACCEPT rateDecrement NUMBER PROMPT 'Enter the rate decrement: '
ACCEPT allowedMinRate NUMBER PROMPT 'Enter the allowed min. rate: '
DECLARE
sr boats%ROWTYPE;
CURSOR sCursor IS
SELECT B.bid, B.bname, B.color, B.rate, B.length, B.logKeeper
FROM Boats B
WHERE B.bid NOT IN (SELECT bid FROM Reservations);
BEGIN
OPEN sCursor;
LOOP
-- Fetch the qualifying rows one by one
FETCH sCursor INTO sr;
EXIT WHEN sCursor%NOTFOUND;
DBMS_OUTPUT.PUT_LINE ('+++++ old rate: '||sr.rate||' '
||sr.rate||);
sr.rate := sr.rate - &rateDecrement;
-- A nested block
DECLARE
belowAllowedMin EXCEPTION;
BEGIN
IF sr.rate < &allowedMinRate
THEN RAISE belowAllowedMin;
ELSE UPDATE Boats
SET rate = sr.rate
WHERE Boats.bid = sr.bid;
-- Print the boat new record
DBMS_OUTPUT.PUT_LINE ('+++++ new row: '||sr.bid||' '
||sr.rate||);
END IF;
EXCEPTION
WHEN belowAllowedMin THEN
DBMS_OUTPUT.PUT_LINE('+++++ Update rejected: '||
'The new rate would have been: '|| sr.rate);
WHEN OTHERS THEN
DBMS_OUTPUT.PUT_LINE('+++++ update rejected: ' ||
SQLCODE||'...'||SQLERRM);
END;
-- end of the nested block
END LOOP;
COMMIT;
CLOSE sCursor;
END;
SELECT S.sid, S.rating
FROM sailors S, reservations R, boats B
WHERE S.sid = R.sid AND
R.bid = B.bid;
UNDEFINE rateDecrement
UNDEFINE allowedMinRate
DBMS_OUTPUT.PUT_LINE ('+++++ new row: '||sr.bid||' '||sr.rate||);
DBMS_OUTPUT.PUT_LINE ('+++++ old rate: '||sr.rate||' '||sr.rate||);
Looks like these 2 are the problem. There should not be '||' at the end.

How to display the highest amount in PL/SQL along with ($) symbol?

Below is my current code in which I have to display on two populated tables called department and employee.
Employee Name: Johnshon
Job: Service Writer
Total Pay: $56,000
========================================
Department Name: Service
Highest Total Pay: $4,500.00
I am having problems getting the highest total pay to get displayed. I think my problem may be where I declared another variable name v_dpay. I'm not sure if I need that or not. I am pretty sure I should use MAX to get the highest total paid in the department. I am also having some problems implementing the ($) and (,) in my output to two decimal places.
ACCEPT p_1 PROMPT 'Please enter the Employee ID:'
DECLARE
v_eid employee.employee_id%TYPE := &p_1;
v_count NUMBER;
v_name employee.employee_name%TYPE;
v_job employee.job%TYPE;
v_pay employee.salary%TYPE;
v_did department.department_id%TYPE;
v_dname department.department_name%TYPE;
v_dpay ?????????????????????????????????
BEGIN
SELECT COUNT(*)
INTO v_count
FROM employee
WHERE employee_id = v_eid;
IF v_count = 0 THEN
DBMS_OUTPUT.PUT_LINE(v_eid || ' is not in the employee table.');
ELSE
select employee_name, job, salary + NVL(commission, 0), department_id
into v_name, v_job, v_pay, v_did
from employee
where employee_id = v_eid;
DBMS_OUTPUT.PUT_LINE('Employee Name: ' || v_name);
DBMS_OUTPUT.PUT_LINE('Job: ' || v_job);
DBMS_OUTPUT.PUT_LINE('Total Pay: ' || v_pay);
if v_did is not null then
select department_name, MAX(v_dpay)
into v_dname, v_dpay
from department, employee
where department_id = v_did;
DBMS_OUTPUT.PUT_LINE('Department Name: ' || v_dname);
DBMS_OUTPUT.PUT_LINE('Highest Total Pay: ' || v_dpay);
else
DBMS_OUTPUT.PUT_LINE('N/A');
end if;
END IF;
END;
Taking the maximum value of v_dpay is just going to give you...the value of v_dpay. I suspect this is not what you wanted. Perhaps the following might help:
SELECT d.DEPARTMENT_NAME, MAX(e.SALARY + NVL(e.COMMISSION, 0))
INTO v_dname, v_dpay
FROM DEPARTMENT d
INNER JOIN EMPLOYEE e
ON (e.DEPARTMENT_ID = d.DEPARTMENT_ID)
WHERE d.DEPARTMENT_ID = v_did;
Based on the posted code this SELECT should get you what you're looking for - and if it doesn't a little tweaking ought to do it.
Share and enjoy.
Bob's covered where you're going wrong with the max calculation; the v_dpay variable cold be declared as employee.salary%TYPE to maych v_pay, or as NUMBER, or another numeric data type. You could re-use v_pay but it's clearer if it has its own variable I think.
For the display, you need the TO_CHAR(number) function:
DBMS_OUTPUT.PUT_LINE('Highest Total Pay: ' || TO_CHAR(v_dpay, 'C999G999G999D99'));
The format model uses C to represent the currency, which will give you $ if your NLS settings are for the US (or other countries that use that symbol!); G for the group separator which will give you , and D for the decimal separator which will give you ., again based on your NLS settings.
A less portable equivalent would be '$999,999,999.99', but using the generic versions isn't a bad habit to get into.