Cursor loop - COUNT from two tables - PLSQL Oracle - oracle

Need some advice here. I have two tables: 1) Car owners; 2) Cars. With cursor loop I need to count how many cars owns each person. I don't understand how do you write the select code when two tables are involved.
CREATE TABLE car_owner(
pnr VARCHAR2(13) PRIMARY KEY,
fname VARCHAR2(20);
CREATE TABLE car(
regnr VARCHAR2(6) PRIMARY KEY,
pnr REFERENCES car_owner(pnr);
INSERT INTO car_owner VALUES('19490321','anna');
INSERT INTO car_owner VALUES('19540201','tomas');
INSERT INTO car_owner VALUES('19650823','roger');
INSERT INTO car VALUES('ase456','19490321');
INSERT INTO car VALUES('ptg889','19490321');
INSERT INTO car VALUES('bon666','19650823');
declare
cursor c_cars is select pnr, fnamn, count(amount_of_cars(pnr))
from car_owner, car;
v_pnr car_owner.pnr%type;
v_fnamn car_owner.fnamn%type;
begin
if not c_cars %isopen then
open c_cars;
end if;
loop
fetch c_cars
into v_pnr, v_fnamn;
exit when c_cars %notfound;
dbms_output.put_line(v_pnr || ', ' || v_fnamn || ', ' ||
', owns: ' || amount_of_cars || ' cars');
end loop;
close c_cars;
end;
So the answer should look like this:
19490321, anna, owns: 2 cars
19540201, tomas, owns: 1 car
19650823, roger, owns: 0 cars

Join those tables. As you're aggregating something, all non-aggregated columns should be part of the group by clause.
Also, consider using a cursor FOR loop as it is way simpler (Oracle does all the dirty job for you - you don't have to declare variable(s), open the cursor, worry about exiting the loop, close the cursor).
SQL> DECLARE
2 CURSOR c_cars IS
3 SELECT o.pnr, o.fname, COUNT (*) cnt
4 FROM car_owner o JOIN car c ON c.pnr = o.pnr
5 GROUP BY o.pnr, o.fname;
6 BEGIN
7 FOR cur_r IN ( SELECT o.pnr, o.fname, COUNT (*) cnt
8 FROM car_owner o JOIN car c ON c.pnr = o.pnr
9 GROUP BY o.pnr, o.fname)
10 LOOP
11 DBMS_OUTPUT.put_line (
12 cur_r.pnr
13 || ', '
14 || cur_r.fname
15 || ', '
16 || ', owns: '
17 || cur_r.cnt
18 || ' car(s)');
19 END LOOP;
20 END;
21 /
19650823, roger, , owns: 1 car(s)
19490321, anna, , owns: 2 car(s)
PL/SQL procedure successfully completed.
SQL>

Related

arrays in pl sql | varray | associative

I'm planning to write a pl sql
pseudo code
procedure a gets all records from emp and is passed to procedure b
procedure b getting called inside from a , is transforming the data from emp , each emp record is traversed 6 times and storing the data in an array
inside procedure b , i used varray (size of 2000 to 2 mil) and also associative array , but it is always failing after handling 10 -15 records .i.e. after handling it for 60 -90 records
i am reusing the same index for storing my data but nothing worked i.e. 1 to 6
I am not sure what i am doing wrong , please assist .
create or replace PROCEDURE query_emp ( bill_cycle_ip in number,
no_of_recs in number ) AS
TYPE billAcnt IS REF CURSOR RETURN emp%ROWTYPE;
ba_rec emp%ROWTYPE;
b_a billAcnt;
total_num_of_rec number ;
BEGIN
OPEN b_a FOR
select * from
(select * from emp where bill_cycle =1 and ban_status in ('O' ,'S')
union
select * from emp where bill_cycle =1 and ban_status in ('N')
and STATUS_LAST_DATE >= sysdate -30
)
where ban not in (Select ban from temp_ba)
and rownum <no_of_recs;
LOOP
FETCH b_a INTO ba_rec;
EXIT WHEN b_a%NOTFOUND;
create_final_snapshot (ba_rec);
END LOOP;
CLOSE b_a;
END;
create or replace procedure create_final_snapshot ( ba_rec IN emp%ROWTYPE ) AS
cur_bl_seq_number number ;
bl_seq_number_minus_six number ;
type total_due_amt is table of number INDEX BY PLS_INTEGER ;
nt total_due_amt := total_due_amt();
b number := 1 ;
BEGIN
cur_bl_seq_number :=ba_rec.BL_CUR_BILL_SEQ_NO ;
if ba_rec.BL_CUR_BILL_SEQ_NO-5 <=1 then
bl_seq_number_minus_six:=1;
else
bl_seq_number_minus_six:=ba_rec.BL_CUR_BILL_SEQ_NO-5;
end if ;
for a in bl_seq_number_minus_six..cur_bl_seq_number
LOOP
--nt.extend();
select xyz into nt(b) from emp_2 where ban =ba_rec.ban and bill_seq_no =a ;
dbms_output.put_line('total_due_amt_list sun= ' ||ba_rec.ban ||' ' || nt(b) || ' bill seq no ' ||a ||' b ' || b );
b := b +1;
END loop;
b:=1;
insert into temp_ba
values (nt(1) ,nt(2), nt(3),nt(4),nt(5),nt(6) );
END;

E-mail result of 'select' statement having multiple rows as result set in ORACLE

I am new to ORACLE PL/SQL world. I am trying to figure out a way to calculate something as below.
Let's say you have a MASTER_TABLE as below :
SELECT * FROM MASTER_TABLE;
+----------+----------+------------------+-----------------------+
| SCHEMA | TABLE_NM | REQUIRED_COLUMNS | TABLE_FILTER |
+----------+----------+------------------+-----------------------+
| USER_SCH | A | A1,A2,A3 | EXAM_DT > SYSDATE - 1 |
| USER_SCH | B | B1,B2 | TRUNC(SYSDATE) |
+----------+----------+------------------+-----------------------+
I would like to generate SELECT query from above table such as below:
SELECT 'SELECT SCHEMA || '.' || TABLE_NM ||' WHERE '|| TABLE_FILTER FROM MASTER_TABLE;
Obviously, the result of above query would generate multiple select statements.
Now, I want to execute all such SELECT statements and send out the resultset via e-mail.
The tricky part is, the columns mentioned in the MASTER_TABLE varies (i.e. For table 'A' there can be 3 REQUIRED_COLUMNS to be selected, For table 'B' there can be 2 REQUIRED_COLUMNS to be selected - As shown in the MASTER_TABLE)
I have the e-mail utility ready which basically takes an argument as your_message and sends it out via e-mail.
Here is what I have tried :
Created CURSOR to generate such select statements.
Tried inserting the resultset (LIST OF SELECT QUERIES) to another temp table by concatenating the columns.
(i.e.
SELECT
'SELECT '
|| replace(required_columns, ',', '||'',''||')
|| ' AS MSG_BDY'
|| ' FROM '
|| schema
|| '.'
|| table_nm
|| ' WHERE '
|| table_filter
as my_select_stmt
FROM
master_table;
I am stuck after this.
Can you please help me out ? or is there any approach to achieve this ?.
Note : Tables mentioned in MASTER_TABLE can have 1 or more rows.
I don't have your tables so I used Scott's.
Master table:
SQL> select * From master_table;
SCHEM TABL REQUIRED_COLUMN TABLE_FILTER
----- ---- --------------- ----------------------
scott emp ename, job, sal hiredate < sysdate - 1
scott dept dname, loc deptno = 20
SQL>
Procedure which simulates your mailing procedure; I'll just display those values.
SQL> CREATE OR REPLACE PROCEDURE p_mail (par_result IN SYS.odcivarchar2list)
2 AS
3 BEGIN
4 FOR i IN par_result.FIRST .. par_result.LAST
5 LOOP
6 DBMS_OUTPUT.put_line (par_result (i));
7 END LOOP;
8 END;
9 /
Procedure created.
SQL>
Procedure you actually need; as you composed the select statement(s), now you only have to run them. In order to do so, use dynamic SQL (e.g. execute immediate):
SQL> SET SERVEROUTPUT ON
SQL>
SQL> DECLARE
2 retval SYS.odcivarchar2list;
3 BEGIN
4 FOR cur_r
5 IN (SELECT 'SELECT '
6 || REPLACE (required_columns, ',', '||'',''||')
7 || ' AS MSG_BDY'
8 || ' FROM '
9 || schema
10 || '.'
11 || table_nm
12 || ' WHERE '
13 || table_filter
14 AS my_select_stmt
15 FROM master_table)
16 LOOP
17 EXECUTE IMMEDIATE cur_r.my_select_stmt BULK COLLECT INTO retval;
18
19 -- you'd call your mailing procedure here
20 p_mail (retval);
21 END LOOP;
22 END;
23 /
SMITH,CLERK,920
ALLEN,SALESMAN,1600
WARD,SALESMAN,1250
JONES,MANAGER,2975
MARTIN,SALESMAN,1250
BLAKE,MANAGER,2850
CLARK,MANAGER,2450
SCOTT,ANALYST,3000
KING,PRESIDENT,10000
TURNER,SALESMAN,1500
ADAMS,CLERK,1300
JAMES,CLERK,950
FORD,ANALYST,3000
MILLER,CLERK,1300
RESEARCH,DALLAS
PL/SQL procedure successfully completed.
SQL>
[EDIT: what if you wanted to display 'null' for missing values?]
Well, that's a new moment - probably not very simple. See if this helps.
In order to help myself, I modified master_table and added ID column to uniquely identify every row. It'll be used to split required columns' list to rows, apply NVL to them, apply CAST to columns (because NVL complains if datatypes don't match), aggregate them back using listagg. As this is quite a lot to do, I'm going to create a view and use it instead of the table itself.
SQL> CREATE OR REPLACE VIEW v_master_table
2 AS
3 SELECT id,
4 schema,
5 table_nm,
6 LISTAGG ('NVL(cast(' || col || ' as varchar2(20)), ''null'')', '||'',''||')
7 WITHIN GROUP (ORDER BY lvl)
8 required_columns,
9 table_filter
10 FROM (SELECT id,
11 schema,
12 table_nm,
13 table_filter,
14 COLUMN_VALUE lvl,
15 TRIM (REGEXP_SUBSTR (required_columns,
16 '[^,]+',
17 1,
18 COLUMN_VALUE))
19 col
20 FROM master_table
21 CROSS JOIN
22 TABLE (
23 CAST (
24 MULTISET (
25 SELECT LEVEL
26 FROM DUAL
27 CONNECT BY LEVEL <=
28 REGEXP_COUNT (required_columns,
29 ',')
30 + 1) AS SYS.odcinumberlist)))
31 GROUP BY id,
32 schema,
33 table_nm,
34 table_filter;
View created.
For example, it now looks like this:
SQL> select * from v_master_table where id = 2;
ID SCHEM TABL REQUIRED_COLUMNS TABLE_FILTER
--- ----- ---- ------------------------------------------------------------------------------------- ------------
2 scott dept NVL(cast(dname as varchar2(20)), 'null')||','||NVL(cast(loc as varchar2(20)), 'null') deptno = 20
SQL>
The mailing procedure remains the same, no change.
Anonymous PL/SQL block is slightly changed - I removed REPLACE you previously used as view does it now; also, source is the view, not the table.
SQL> alter session set nls_date_format = 'dd.mm.yyyy';
Session altered.
SQL> DECLARE
2 retval SYS.odcivarchar2list;
3 BEGIN
4 FOR cur_r
5 IN (SELECT 'SELECT '
6 || required_columns
7 || ' AS MSG_BDY'
8 || ' FROM '
9 || schema
10 || '.'
11 || table_nm
12 || ' WHERE '
13 || table_filter
14 AS my_select_stmt
15 FROM v_master_table)
16 LOOP
17 EXECUTE IMMEDIATE cur_r.my_select_stmt BULK COLLECT INTO retval;
18
19 -- you'd call your mailing procedure here
20 p_mail (retval);
21 END LOOP;
22 END;
23 /
CLARK,09.06.1981,null
KING,17.11.1981,null
MILLER,23.01.1982,null
RESEARCH,DALLAS
PL/SQL procedure successfully completed.
SQL>

Search data from any column of the table from Oracle

I want to implement one search logic here. What I want is,
A user enters any text in the search box and presses enter. Then what should happen is, it should search in the table on any column and it the record exist then it should display.
Currently what I tried is, it search from one of the column from the table. Below is the code,
PROCEDURE GET_SEARCH_DATA
(
P_INPUTTEXT IN NVARCHAR2,
P_RETURN OUT SYS_REFCURSOR
)
AS
BEGIN
OPEN P_RETURN FOR
SELECT APP_MST_ID, APPLICATIONNAME, PROJECTNO, VSS_FOLDER_LOC FROM
APPLICATION_MASTER WHERE APPLICATIONNAME LIKE '%'|| P_INPUTTEXT || '%';
END;
So what I want is, it should search from every column of the table and display the result.
This is a rather rudimentary "solution" which checks all tables and their columns (from USER_TAB_COLUMNS) and checks which ones of them contain a search string; it displays a table, a column and number of occurrences.
SQL> declare
2 l_str varchar2 (500);
3 l_cnt number := 0;
4 begin
5 for cur_r in (select u.table_name, u.column_name
6 from user_tab_columns u)
7 loop
8 l_str :=
9 'SELECT COUNT(*) FROM '
10 || cur_r.table_name
11 || ' WHERE '
12 || upper (cur_r.column_name)
13 || ' like (''%&search_string%'')';
14
15 execute immediate (l_str) into l_cnt;
16
17 if l_cnt > 0
18 then
19 dbms_output.put_line (
20 cur_r.table_name || '.' || cur_r.column_name || ': ' || l_cnt);
21 end if;
22 end loop;
23 end;
24 /
Enter value for search_string: MANAGE
EMP.JOB: 3
PL/SQL procedure successfully completed.
SQL> /
Enter value for search_string: ACCOU
DEPT.DNAME: 1
PL/SQL procedure successfully completed.
SQL>

How to fetch cursor values from pivot SQL to fixed variables - Error ORA-01007

I have a SQL statement with the PIVOT operation. The maximum number of columns I will have in PIVOT is 5, but I can have less, 4, 3, 2.
How can I read these columns in my cursor and assign (fetch .. into...) to the fixed variables, without occurring the error ORA-01007.
...
sql_stmt := 'select * from
(select codcoligada,
idprd,
codcfo,
valnegociado
from tcitmorcamento
where codcoligada = ' || p_codcoligada || '
and codcotacao = ' || '''' || p_codcotacao || '''' || ')
pivot
(
sum(valnegociado) for codcfo in (' || pivot_clause || ')
)';
ret := t_tab_sesa_cotacao();
open vCursor for sql_stmt;
loop
/* If my cursor returns less than 5 columns in PIVOT the error occurs ORA-01007 */
fetch vCursor into vCodColigada, vIdProduto, vValor01, vValor02, vValor03, vValor04, vValor05;
exit when vCursor%NOTFOUND;
ret.extend;
ret(ret.count) := t_type_sesa_cotacao(vCodColigada, vIdProduto, vValor01, vValor02, vValor03, vValor04, vValor05);
end loop;
close vCursor;
...
If I return less than 5 colums, I want to fill in the remainder of the variables with a value of 0 or null.
The variables vCodColigada and vIdProduto are identified, only PIVOT columns that can vary between 1 and 5 (vValor1, vValor2, vValor3, vValor4, vValor5)
Result PIVOT SQL:
CODCOLIGADA IDPRD '000125' '002272' '002342'
----------------- ---------------- ---------------- ---------------- ----------------
1 15464 45 300 30
1 18460 35 200 20
1 57492 20 100 10
-------- End of Data --------
Example:
If the cursor returns 3 values in the PIVOT (above), the variables vValor01, vValor02, vValor03 will be filled in, and the variables vValor04, vValor05 must be 0 or null.
Example:
CODCOLIGADA IDPRD VALOR01 VALOR02 VALOR03 VALOR04 VALOR05
----------------- ---------------- ---------------- ---------------- ---------------- ---------------- ----------------
1 15464 45 300 30 0 0
1 18460 35 200 20 0 0
1 57492 20 100 10 0 0
-------- End of Data --------
As I only have 3 columns in PIVOT, and I have 5 variables, the ORA-01007 error occurs in (fetch .. into ...).
Hope this below snippet helps. What the basic understanding is we need to add excess variable as null or blank to make this work.
SET serveroutput ON;
DECLARE
lv_pivot VARCHAR2(100):='''Y'',''N''';
TYPE lv
IS
RECORD
(
flg_y VARCHAR2(100),
flg_n VARCHAR2(100),
flg_e VARCHAR2(100));
type lv_tab
IS
TABLE OF lv;
lv_num lv_tab;
lv_check VARCHAR2(1000);
BEGIN
lv_check :=regexp_count(lv_pivot,',',1);
IF lv_check < 3 THEN
FOR z IN 1..(2-lv_check)
LOOP
lv_pivot:=lv_pivot||',null as val'||z;
END LOOP;
ELSE
lv_pivot:=lv_pivot;
END IF;
dbms_output.put_line(lv_pivot);
EXECUTE IMMEDIATE ' SELECT * FROM
(SELECT col1 FROM <table> )
pivot ( COUNT(1) FOR col1 IN ('||lv_pivot||'))' BULK COLLECT INTO lv_num;
END;
---------------------------Refactoring in Function------------------------------
--Create Object Type
CREATE OR REPLACE TYPE lv_obj IS OBJECT
(
flg_y VARCHAR2(100),
flg_n VARCHAR2(100),
flg_e VARCHAR2(100)
);
--Create Table Type
CREATE OR REPLACE TYPE lv_tab IS TABLE OF lv_obj;
--Create Function
CREATE OR REPLACE
FUNCTION test_func
RETURN lv_tab
AS
lv_pivot VARCHAR2(100):='''Y'',''N''';
lv_num lv_tab;
lv_check VARCHAR2(1000);
BEGIN
lv_check :=regexp_count(lv_pivot,',',1);
IF lv_check < 3 THEN
FOR z IN 1..(2-lv_check)
LOOP
lv_pivot:=lv_pivot||',null as val'||z;
END LOOP;
ELSE
lv_pivot:=lv_pivot;
END IF;
dbms_output.put_line(lv_pivot);
EXECUTE IMMEDIATE ' SELECT * FROM
(SELECT col1 FROM <table> )
pivot ( COUNT(1) FOR col1 IN ('||lv_pivot||'))' BULK COLLECT INTO lv_num;
RETURN lv_tab;
END;
-------------------------------------------------Output-----------------------------------------------
SELECT * FROM TABLE(test_func);
-------------------------------------------------------------------------------------------------------
Try padding the results in the query. Add a join to a select from dual statement that passes back all five columns.

pl/sql nested loop

How would I display all records in the database using the items table? My current query displays the information for item 894. I attempted using a loop, but no luck.
I have two tables, inventory and itemid. Where itemid has the item number and the description, and the inventory table has the items' information, such as size, color, price, and quantity on hand.
set serveroutput on
DECLARE
current_item number(8);
totalvalue number(8,2);
description varchar2(50);
item_id number(3);
CURSOR Inventory_Info IS
SELECT
itemsize
,color
,curr_price
,qoh
,curr_price*qoh as Total
FROM inventory
WHERE itemid=Current_item;
BEGIN
current_item:=894;
totalvAlue:=0;
SELECT
itemdesc, itemid
INTO description, item_id
FROM item
WHERE itemid=current_item;
DBMS_OUTPUT.PUT_LINE('Item ID: ' || TO_CHAR(item_id) || ' Item Description: ' || description);
OPEN Inventory_Info;
LOOP
Fetch Inventory_Info INTO Inventory_rocord;
EXIT WHEN Inventory_Info%NOTFOUND;
DBMS_OUTPUT.PUT_LINE('Size: ' || Inventory_record.itemsize);
DBMS_OUTPUT.PUT_LINE('Color: ' || Inventory_record.color);
DBMS_OUTPUT.PUT_LINE('Price: ' || Inventory_record.curr_price);
DBMS_OUTPUT.PUT_LINE('QOH: ' || Inventory_record.qoh);
DBMS_OUTPUT.PUT_LINE('Value: ' || Inventory_record.total);
TotalValue:=TotalValue + Inventory_record.total;
End Loop;
DBMS_OUTPUT.PUT_LINE('TOTAL VALUE: ' || TotalValue);
Close Inventory_Info;
EXCEPTION
WHEN NO_DATA_FOUND THEN
DBMS_OUTPUT.PUT_LINE('No inventory for Item No. '|| current_item);
WHEN OTHERS THEN
DBMS_OUTPUT.PUT_LINE('Error Message: '|| SQLERRM);
END;
If we for a moment forget about the formatting this could be done much simpler with a cursor for loop.
set serveroutput ON
DECLARE
BEGIN
FOR item_rec IN (SELECT itemdesc, itemid
FROM item
) LOOP
DBMS_OUTPUT.PUT_LINE('Item ID: ' || TO_CHAR(item_rec.itemid)
|| ' Item Description: ' || item_rec.itemdesc);
FOR Inventory_record IN (SELECT itemsize
, color
, curr_price
, qoh
, curr_price*qoh AS Total
FROM inventory
WHERE itemid = item_rec.itemid
) LOOP
DBMS_OUTPUT.PUT_LINE('Size: ' || Inventory_record.itemsize);
DBMS_OUTPUT.PUT_LINE('Color: ' || Inventory_record.color);
DBMS_OUTPUT.PUT_LINE('Price: ' || Inventory_record.curr_price);
DBMS_OUTPUT.PUT_LINE('QOH: ' || Inventory_record.qoh);
DBMS_OUTPUT.PUT_LINE('Value: ' || Inventory_record.total);
TotalValue:= TotalValue + Inventory_record.total;
END LOOP;
END LOOP;
END;
You're using a separate SELECT..INTO to fetch the itemid, but you assign the itemid to a single value and don't change that.
Looking at your queries, you can move the itemid fetch into the cursor & join the 2 tables. You fetch the items into inventory_record, but I don't see the definition/declaration of that anywhere.
Here I declare a record type variable consisting of what you're fetching, open the cursor, fetch the details into that cursor. Since there's no explicit where condition, it will perform an inner join between item & inventory tables & fetch all rows matching the join condition.
set serveroutput ON
DECLARE
TYPE inventory_rec IS RECORD (
itemid item.itemid%TYPE,
itemdesc item.itemdesc%TYPE,
itemsize inventory.itemsize%TYPE,
color inventory.color%TYPE,
curr_price inventory.curr_price%TYPE,
qoh inventory.qoh %TYPE,
total inventory.curr_price%TYPE); -- record type to hold what cursor will be fetching
inventory_record INVENTORY_REC;
current_item NUMBER(8);
totalvalue NUMBER(8, 2);
description VARCHAR2(50);
item_id NUMBER(3);
CURSOR inventory_info IS
SELECT itemid,
itemdesc,
itemsize,
color,
curr_price,
qoh,
curr_price * qoh AS Total
FROM inventory
join item USING (itemid);
-- join item & inventory, so that it shows listings for all items present in inventory
BEGIN
OPEN inventory_info;
LOOP
FETCH inventory_info INTO inventory_record;
EXIT WHEN inventory_info%NOTFOUND;
dbms_output.Put_line('Current item: '
|| inventory_record.itemdesc);
dbms_output.Put_line('Size: '
|| inventory_record.itemsize);
dbms_output.Put_line('Color: '
|| inventory_record.color);
dbms_output.Put_line('Price: '
|| inventory_record.curr_price);
dbms_output.Put_line('QOH: '
|| inventory_record.qoh);
dbms_output.Put_line('Value: '
|| inventory_record.total);
totalvalue := totalvalue + inventory_record.total;
END LOOP;
dbms_output.Put_line('TOTAL VALUE: '
|| totalvalue);
CLOSE inventory_info;
EXCEPTION
WHEN no_data_found THEN
dbms_output.Put_line('No inventory for Item No. '
|| current_item);
WHEN OTHERS THEN
dbms_output.Put_line('Error Message: '
|| SQLERRM);
END;
Don't use nested look-ups, use joins. Databases are really good at joins, and the performance of set operations is a lot a better than row-by-row processing.
Also, you don't need to declare cursors and variables in most situations. Use a cursor loop and let Oracle do the heavy lifting for you.
set serveroutput on
DECLARE
totalvalue number(8,2);
BEGIN
totalvAlue:=0;
FOR inv_itm_rec IN (
SELECT itm.itemid
, itm.itemdesc
, inv.itemsize
, inv.color
,inv.curr_price
,inv.qoh
,inv.curr_price*inv.qoh as Total
FROM inventory inv
JOIN item itm
ON itm.itemid=inv.itemid
)
LOOP
DBMS_OUTPUT.PUT_LINE('ItemId: ' || inv_itm_rec.itemid);
DBMS_OUTPUT.PUT_LINE('Description: ' || inv_itm_rec.itemdesc);
DBMS_OUTPUT.PUT_LINE('Size: ' || inv_itm_rec.itemsize);
DBMS_OUTPUT.PUT_LINE('Color: ' || inv_itm_rec.color);
DBMS_OUTPUT.PUT_LINE('Price: ' || inv_itm_rec.curr_price);
DBMS_OUTPUT.PUT_LINE('QOH: ' || inv_itm_rec.qoh);
DBMS_OUTPUT.PUT_LINE('Value: ' || inv_itm_rec.total);
TotalValue:=TotalValue + inv_itm_rec.total;
END LOOP;
DBMS_OUTPUT.PUT_LINE('TOTAL VALUE: ' || TotalValue);
END;
Note, this solution assumes that evry ITEM does have a matching INVENTORY record. It would be a rum old warehouse application if the data model allowed anything else to be the case.
If it's just a report(it seems to be). Consider using sql*plus report formatting commands to display the output of a query in a way you want it to be displayed.
Here is an example:
SQL> create table Items(
2 i_num number,
3 i_descr varchar2(101),
4 i_size varchar2(3),
5 i_price number,
6 i_qoh number
7 );
Table created
SQL> create table Inventories(
2 id number,
3 i_num number
4 );
Table created
SQL> insert into items(i_num,i_size,i_price,i_qoh,i_descr)
2 select 1, 'S', 123, 25, 'Item_1' from dual union all
3 select 2, 'L', 424, 12, 'Item_1' from dual union all
4 select 4, 'S', 45, 54, 'Item_4' from dual union all
5 select 5, 'S', 78, 54, 'Item_4' from dual union all
6 select 6, 'S', 123, 22, 'Item_5' from dual union all
7 select 7, 'S', 127, 65, 'Item_5' from dual
8 ;
6 rows inserted
SQL> commit;
Commit complete
SQL> insert into inventories
2 select i_num, i_num
3 from items;
6 rows inserted
SQL> commit;
Commit complete
And now our report:
SQL> column i_descr format a10
SQL> column i_size format a3
SQL> column i_price format 99999
SQL> column i_qoh format 99999
SQL> column value format 99999
SQL> break on i_descr skip 2
SQL> compute sum label 'Total: ' of value on i_descr;
SQL> select itm.i_descr
2 , itm.i_size
3 , itm.i_price
4 , itm.i_qoh
5 , sum(i_price*i_qoh) Value
6 from inventories inv
7 join items itm on (inv.i_num = itm.i_num)
8 group by itm.i_num
9 , itm.i_descr
10 , itm.i_size
11 , itm.i_price
12 , itm.i_qoh
13 order by i_descr, i_price;
I_DESCR I_S I_PRICE I_QOH VALUE
---------- --- ---------- ------ ------
Item_1 S 123 25 3075
L 424 12 5088
********** ------
Total: 8163
Item_4 L 45 54 2430
S 78 54 4212
********** ------
Total: 6642
Item_5 S 123 22 2706
L 127 65 8255
********** ------
Total: 10961
6 rows selected.

Resources