Looking at IF, WHERE, and WHEN in PL SQL - 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;
/

Related

adding to variables inside of a oracle procedure

I created a procedure that takes the account number of a user and it returns every transaction they've made plus their running balance. everything works except the balance. The code compiles and runs but nothing shows up in the running balance column of the dbms.output
CREATE OR REPLACE PROCEDURE print_dett(
in_account_nbr NUMBER
)
IS
dCount NUMBER;
BEGIN
dbms_output.put_line(' Date : transaction amount : balance - For: ' || in_account_nbr);
FOR r IN(
SELECT t.tx_nbr, t.tx_date, t.tx_amount, t.tx_type_code, a.balance
FROM transaction t, account a
WHERE t.account_nbr = a.account_nbr
AND t.account_nbr = in_account_nbr
ORDER BY tx_date)
LOOP
IF r.tx_type_code = 'D' OR r.tx_type_code = 'R' THEN
dCount := dCount + r.tx_amount;
ELSE
dCount := dCount - r.tx_amount;
END IF;
dbms_output.put_line(r.tx_date || ' : ' || r.tx_amount || ' : ' || dCount );
END LOOP;
END;
What can I change in the code so the running balance will actually show up when printed?
Number variables get initialized with NULL. Your variable dCount is hence null first and adding values doesn't change this.
Initialize it with zero instead:
CREATE OR REPLACE PROCEDURE print_dett(
in_account_nbr NUMBER
)
IS
dCount NUMBER := 0;
...

PL/SQL: Cursor doubles the last record from the table

I created the following PL/SQL anonymous block. The cursor below retrieves data from the select statement:
select mod_benutzer, count(*)
from dok_auspraegung
where parent_objekt_id = 1093
group by mod_benutzer;
This statement displays exactly two records:
DDMS_USER | 8
HU2MAMU | 14
But when I want to display these two records by cursor, it displays "HU2MAMU|14" two times like below:
Modifications:
DDMS_USER, 8x
HU2MAMU, 14x
HU2MAMU, 14x
declare
my_exception_1 exception;
var_parent_objekt_id dok_auspraegung.parent_objekt_id%TYPE := 1093;
var_date varchar(30);
var_mod_benutzer varchar2(10);
var_benutzer_modifs number;
cursor cursor_dok_auspraegung
is select mod_benutzer, count(*) from dok_auspraegung
where parent_objekt_id = 10935797565
group by mod_benutzer;
begin
select distinct to_char(mod_datum,'YYYY-MON-DD') into var_date from dok_auspraegung where parent_objekt_id = var_parent_objekt_id;
IF var_date is not null THEN
dbms_output.put_line('Parent Object ID' || ': ' || var_parent_objekt_id);
dbms_output.put_line('Date: ' || ' ' || var_date);
ELSE RAISE my_exception_1;
END IF;
open cursor_dok_auspraegung;
dbms_output.put_line('Modifications:');
loop
fetch cursor_dok_auspraegung into var_mod_benutzer, var_benutzer_modifs;
dbms_output.put(var_mod_benutzer);
dbms_output.put_line(', ' || var_benutzer_modifs || 'x');
exit when cursor_dok_auspraegung%notfound;
end loop;
dbms_output.put_line(cursor_dok_auspraegung%rowcount);
close cursor_dok_auspraegung;
exception
when NO_DATA_FOUND then
dbms_output.put_line('Parent Object ID not found!');
when my_exception_1 then
dbms_output.put_line('');
end;
What is the reason of that?
Because exiting from the cursor occurs after printing the value of the variables in the current case, this repeats the last value to be printed. So, it should occur before printing as follows
loop
fetch cursor_dok_auspraegung into var_mod_benutzer, var_benutzer_modifs;
exit when cursor_dok_auspraegung%notfound;
dbms_output.put(var_mod_benutzer);
dbms_output.put_line(', ' || var_benutzer_modifs || 'x');
end loop;

For loop using VARCHAR2

I'm trying to display the info for each student using this code
DECLARE
CURSOR cursor1 IS SELECT STUDENTNAME, COURSEID, COURSEDESCRIPTION, COURSECREDITS, GRADE
FROM STUDENTINFO;
S_NAME STUDENTINFO.STUDENTNAME%TYPE;
S_COURSEID STUDENTINFO.COURSEID%TYPE;
S_COURSEDESCRIPTION STUDENTINFO.COURSEDESCRIPTION%TYPE;
S_COURSECREDITS STUDENTINFO.COURSECREDITS%TYPE;
S_GRADE STUDENTINFO.GRADE%TYPE;
BEGIN
OPEN CURSOR1;
LOOP
FETCH CURSOR1 INTO S_NAME, S_COURSEID, S_COURSEDESCRIPTION, S_COURSECREDITS, S_GRADE;
EXIT WHEN cursor1%NOTFOUND;
DBMS_OUTPUT.PUT_LINE('Student Name: ' || S_NAME);
DBMS_OUTPUT.PUT_LINE(S_COURSEID || S_COURSEDESCRIPTION || S_COURSECREDITS || S_GRADE);
DBMS_OUTPUT.PUT_LINE(CHR(10));
END LOOP;
CLOSE CURSOR1;
END;
/
My output should be similar to
Student Name: John
CMIS 101 Intro to Info. Systems 3 B
CMIS 301 System Analysis 3 C
CMIS 451 Client/Server Systems 3 C
I'm pretty sure I should be using a for loop which I created
DECLARE
CURSOR cursor2 IS SELECT STUDENTNAME, COURSEID, COURSEDESCRIPTION, COURSECREDITS, GRADE
FROM STUDENTINFO;
search_student STUDENTINFO.STUDENTNAME%TYPE;
BEGIN
FOR v_Record IN cursor2
LOOP
IF v_Record.STUDENTNAME = &SEARCH_STUDENT THEN
DBMS_OUTPUT.PUT_LINE('Student Name: ' || STUDENTNAME);
DBMS_OUTPUT.PUT_LINE(COURSEID || COURSEDESCRIPTION || COURSECREDITS || GRADE);
DBMS_OUTPUT.PUT_LINE(CHR(10));
END IF;
END LOOP;
END;
/
However, when I type in a name for search_student, I'm just given the error
Identifier "insertnamehere"
Can I not use VARCHAR2 when searching? Is it only usable with numbers?
There are a few issues with your code.
For a start, why use PL/SQL to do this? You should just use a SQL statement directly. I'm going to assume that this is a homework question though (*sigh* - surely there are better examples to use?!).
1. IF v_Record.STUDENTNAME = &SEARCH_STUDENT - when you pass in a value for search_student, the client replaces the term &search_student. So, either you must ensure that the single quotes to specify the studentname is a string when you define the search_student (ie. when prompted for search_student you enter "'SomeName'") OR put the single quotes around the &SEARCH_STUDENT - ie. IF v_Record.STUDENTNAME = '&SEARCH_STUDENT'
2. When referencing the fields returned by the cursor in the for loop, you need to reference the record that the values were fetched into. Therefore DBMS_OUTPUT.PUT_LINE('Student Name: ' || STUDENTNAME); should be DBMS_OUTPUT.PUT_LINE('Student Name: ' || v_Record.STUDENTNAME);
3. Finally, if you're looking to output a single student record at a time, put the filter in the cursor, not in the loop.

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.

PL/SQL Storing and calling procedure

I am currently working on a PL/SQL problem where I have to create a cursor inside a procedure that will give the appropriate discount for a given item (10% for prices >= $100 and 5% for prices >= $10). When I have to call the procedure, I need to display the Order Number, customer First Name, Last Name, and the Total Net Cost of the items after the discount for a specific order number (in this case I need to display for order number 2). I can't get it to display this information.
Here is my code for creating the procedure with a cursor so far.
CREATE OR REPLACE PROCEDURE ComputeOrderTotal
(no_id IN orders.o_id%TYPE,
cfirst IN customer.c_first%TYPE,
clast IN customer.c_last%TYPE,
TotalNetCost OUT orders.ordertotal%TYPE) IS
CURSOR OrderCursor IS
SELECT order_line.inv_id, inv_price, ol_quantity, inv_price*ol_quantity AS ExtPrice,
CASE
WHEN inv_price*ol_quantity >= 100 THEN 0.9*(inv_price*ol_quantity)
WHEN inv_price*ol_quantity >= 10 THEN 0.95*(inv_price*ol_quantity)
ELSE
inv_price*ol_quantity
END AS NetCost
FROM inventory, order_line, orders, customer
WHERE orders.o_id = customer.c_id;
OrderRow OrderCursor%ROWTYPE;
BEGIN
OPEN OrderCursor;
LOOP
FETCH OrderCursor INTO OrderRow;
EXIT WHEN OrderCursor%NOTFOUND;
TotalNetCost :=TotalNetCost + OrderRow.NetCost;
END LOOP;
DBMS_OUTPUT.PUT_LINE('Order Number: ' || no_id || 'First Name: ' || cfirst || 'Last Name: ' ||
clast || 'Total Net Cost: ' || TO_CHAR(TotalNetCost, '$0999.99'));
END;
And here is my code for calling the procedure.
DECLARE
no_id orders.o_id%TYPE;
cfirst customer.c_first%TYPE;
clast customer.c_last%TYPE;
TotalNetCost orders.ordertotal%TYPE;
BEGIN
ComputeOrderTotal(2, cfirst, clast, TotalNetCost);
END;
Thanks for the help!
i am not sure but your conditions could be the problem as your second condition contradicts the first. for example 110 satisfy the first condition but it also satisfy the second condition.
WHEN inv_price*ol_quantity >= 100 THEN 0.9*(inv_price*ol_quantity)
WHEN inv_price*ol_quantity >= 10 THEN 0.95*(inv_price*ol_quantity)
i would suggest changing second condition to <100 and >=10
Add this line to the top of the code calling the procedure.
Alter session set serveroutput on;