PL/SQL Variable parameters in procedure - sql

I need to create a procedure that allows a user to input information for an order (which is below), but also for n number of suborders (where 2 ≤ n ≥ 10). How would I be able to incorporate this into the procedure I already have? I'm using SQLPlus. Any help or advice would be greatly appreciated. :)
CREATE OR REPLACE PROCEDURE VIEW_ORDER(ORDERS IN CHAR)
AS
CURSOR ORDER_CUR IS
SELECT * FROM SUBORDERS
WHERE ORDER_NO = ORDERS;
BEGIN
FOR O_REC IN ORDER_CUR
LOOP
DBMS_OUTPUT.PUT_LINE('Product Code: ' || O_REC.prod_id
|| ' Order: ' || O_REC.order_no
|| ' Suborder: ' || O_REC.suborder_no
|| ' Quantity: ' || O_REC.quantity);
END LOOP;
EXCEPTION
WHEN no_data_found THEN
DBMS_OUTPUT.PUT_LINE ('Product number does not exist');
WHEN OTHERS THEN DBMS_OUTPUT.PUT_LINE ('Operation failed ' || 'SQLCODE: ' || SQLCODE);
ROLLBACK;
END;
/

You can use for an input sqlplus command ACCEPT and make another loop to take n suborders.
If I didn't missunderstood your question it would be something like this:
-- You have to create the input outside the procedure
accept n char prompt 'Please enter n suborders: '
CREATE OR REPLACE PROCEDURE VIEW_ORDER(ORDERS IN CHAR)
AS
CURSOR ORDER_CUR IS
SELECT * FROM SUBORDERS
WHERE ORDER_NO = ORDERS;
BEGIN
FOR O_REC IN ORDER_CUR
LOOP
-- Here we check if n<=2
IF n>=2 THEN
-- here if n<=10
WHILE n<=10
LOOP
DBMS_OUTPUT.PUT_LINE('Product Code: ' || O_REC.prod_id
|| ' Order: ' || O_REC.order_no
|| ' Suborder: ' || O_REC.suborder_no
|| ' Quantity: ' || O_REC.quantity);
END LOOP;
END IF;
END LOOP;
EXCEPTION
WHEN no_data_found THEN
DBMS_OUTPUT.PUT_LINE ('Product number does not exist');
WHEN OTHERS THEN DBMS_OUTPUT.PUT_LINE ('Operation failed ' || 'SQLCODE: '
||
SQLCODE);
ROLLBACK;
END;
/

Related

HOW TO ADD HEADER AND FOOTER AT THE OF THE CODE TO GET THE REQUIRED O/P

Write a procedure to genearte a report of all employee with managers name details with | (pipe delimiter) in unix development server /tmp path.
Example:**
Emp ID|Emp Name|Manager Name|Sal|Dept No|Location -------header**
7369|SMITH|FORD|800|20|DALLAS
Total Record|1 ------Trailer
f_handle2 utl_file.file_type;
begin
f_handle2 := utl_file.fopen(
'TESTING_DIR' -- File location
, 'EMP_DET_WITH_MANA_NAME2' -- File name
, 'w'); -- Open mode: w = write.
for i in (select empno,ename,manager_name,sal,deptno,loc,count(empno) from t77)
loop
utl_file.putf(f_handle2,i.empno||'|'||i.ename||'|'||i.manager_name||'|'||i.sal||'|'||i.deptno||'"'||i.loc);
UTL_FILE.NEW_LINE(f_handle2);
end loop;
utl_file.fclose(f_handle2);
exception
when others then
dbms_output.put_line('ERROR: ' || SQLCODE || ' - ' || SQLERRM);
raise;
end;

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;

PL/SQL Cursors - Retrieving data from multiple tables

I need to input a product code as a parameter that will retrieve said product and other information. I require more info than I have provided, I've started small scale to attempt to debug any errors early, but I cannot see why the code below doesn't work. I'm using SQLPlus, any help would be greatly appreciated.
CREATE OR REPLACE PROCEDURE product_info(PRODUCT_NO IN CHAR)
AS
v_product PRODUCTS%ROWTYPE;
v_suborders SUBORDERS.ORDER_NO%TYPE;
CURSOR cur_products IS
SELECT p.name, p.prod_id, p.description, p.unit_price, s.order_no
FROM PRODUCTS P, SUBORDERS S
WHERE p.prod_id = product_no;
BEGIN
OPEN cur_products;
LOOP
FETCH cur_products INTO v_product, v_suborders;
DBMS_OUTPUT.PUT_LINE('Product Code: ' || v_product.prod_id
|| ' Name: ' || v_product.name
|| ' Description: ' || v_product.description
|| ' Price: ' || v_product.unit_price
|| ' Order: ' || v_suborders);
END LOOP;
EXCEPTION
WHEN no_data_found THEN
DBMS_OUTPUT.PUT_LINE ('Product number does not exist');
WHEN OTHERS THEN DBMS_OUTPUT.PUT_LINE ('Operation failed ' || 'SQLCODE: ' || SQLCODE);
ROLLBACK;
END;
/
When we fetch into a variable its structure must match the projection of the query we're fetching. Or if we're fetching into multiple variables we need one variable per column in the projection. Your code doesn't do either.
The simplest solution is to use your cursor to define the variable, like this:
CURSOR cur_products IS
SELECT p.name, p.prod_id, p.description, p.unit_price, s.order_no
FROM PRODUCTS P, SUBORDERS S
WHERE p.prod_id = product_no;
v_rec cur_products%ROWTYPE;
BEGIN
OPEN cur_products;
LOOP
FETCH cur_products INTO v_rec;
...
An alternate solution is to use an implicit cursor. You could rewrite your code like this:
CREATE OR REPLACE PROCEDURE product_info(PRODUCT_NO IN CHAR)
AS
BEGIN
for v_rec in (SELECT p.name, p.prod_id, p.description, p.unit_price, s.order_no
FROM PRODUCTS P, SUBORDERS S
WHERE p.prod_id = product_no )
LOOP
DBMS_OUTPUT.PUT_LINE('Product Code: ' || v_rec.prod_id
|| ' Name: ' || v_rec.name
|| ' Description: ' || v_rec.description
|| ' Price: ' || v_rec.unit_price
|| ' Order: ' || v_rec.odrer_no);
END LOOP;
EXCEPTION
WHEN no_data_found THEN
DBMS_OUTPUT.PUT_LINE ('Product number does not exist');
WHEN OTHERS THEN DBMS_OUTPUT.PUT_LINE ('Operation failed ' || 'SQLCODE: ' || SQLCODE);
ROLLBACK;
END;
/
Incidentally, you query doesn't have a join between PRODUCTS and SUBORDERS so your result set will be a product (cross-join) or all the records in both tables. Almost certainly you don't want that.
Also, it is bad practice not to re-raise an exception in the exception handler (apart from some edge cases). It doesn't matter in a piece of toy code like this, but don't fall into bad habits.

Looping statement

I am working on a loop to bring back the times tables from 1-12. I have completed this by using the following:
BEGIN
FOR i IN 1..12
LOOP
FOR j IN (i)..12
LOOP
dbms_output.put_line ( (i ) || '*' || (j ) || ('=') || (i*j) );
END LOOP;
END LOOP;
END;
/
And it brings back:
1*1=1
1*2=2
1*3=3
1*4=4
1*5=5
1*6=6
1*7=7
1*8=8
1*9=9
1*10=10
1*11=11
1*12=12
2*2=4
2*3=6
2*4=8
etc..
it brings back all the times tables like i wanted. Now i want it to bring back a title for each set, how would i do this? for e.g.
1 timetable
1*1=1
1*2=2
1*3=3
1*4=4
1*5=5
1*6=6
1*7=7
1*8=8
1*9=9
1*10=10
1*11=11
1*12=12
2 timestable
2*2=4
2*3=6
2*4=8
Is this possible?
Thanks
Try;
BEGIN
FOR i IN 1..12 LOOP
dbms_output.put_line(to_char(i) || ' timetable');
FOR j IN (i)..12 LOOP
dbms_output.put_line ( (i ) || '*' || (j ) || ('=') || (i*j) );
END LOOP;
END LOOP;
END;
/

PLSQL does not compile when substracting two long variables

I'm writing a pretty basic procedure where I need to substract two long variables and assign the value to the other variable. But the code doesn't compile and I am getting hopeless - why is that?
create or replace PROCEDURE TrendCalculator(p_id Prodeje.product%TYPE)
AS
v_week_last Prodeje.WEEK%TYPE;
v_week_current Prodeje.WEEK%TYPE;
v_year_last Prodeje.YEAR%TYPE;
v_year_current Prodeje.YEAR%TYPE;
v_weekly_sales_last PRODEJE.SALES%TYPE;
v_weekly_sales_current PRODEJE.SALES%TYPE;
v_pomocna PRODEJE.SALES%TYPE;
CURSOR c_data IS SELECT WEEK, YEAR, SALES FROM Prodeje WHERE PRODUCT = p_id ORDER BY YEAR, WEEK ASC;
BEGIN
v_pomocna := 0;
OPEN c_data;
LOOP
FETCH c_data INTO v_week_current, v_year_current, v_weekly_sales_current;
EXIT WHEN c_data%NOTFOUND;
IF (v_weekly_sales_last IS NOT NULL) THEN
DBMS_OUTPUT.PUT_LINE(p_id || ' ' || v_week_current || ' ' || v_year_current || ' ' || v_weekly_sales_current);
v_pomocna := (v_weekly_sales_current - v_weekly_sales_last);
END IF;
v_week_last := v_week_current;
v_year_last := v_year_current;
v_weekly_sales_last := v_weekly_sales_current;
END LOOP;
CLOSE c_data;
END;
The Error messages I'm getting are:
Error(19,9): PL/SQL: Statement ignored
Error(19,95): PLS-00306: wrong number or types of arguments in call to '-'
And PRODEJE.SALES Datatype is LONG.
v_weekly_sales_last is not set to anything. So line 19 evaluates to
v_pomocna := (v_weekly_sales_current - );
Which seems to be the cause of your error.