(Oracle) How to get sum value inside loop? - oracle

I need value of sum inside loop.
DECLARE
VAR_PCT NUMBER;
CURSOR C1 IS
SELECT A, B FROM TBL;
BEGIN
FOR REC1 IN C1
LOOP
--This where i need the value of sum(rec1.b) to calculate VAR_PCT:=(REC1.B/SUM(REC1.B))*100
DBMS_OUTPUT.PUT_LINE(REC1.A ||'|'|| REC1.B ||'|'||VAR_PCT)
END LOOP;
END;
So, I basically need to figure out how to get the sum of B.
EDIT:
I forgot that I have one more variable that accumulate before the sum
*FOR REC1 IN C1
LOOP*
VAR_X := VAR_X+REC1.B
*--This where i need the value of sum(rec1.b) to calculate VAR_PCT:=(REC1.B/SUM(REC1.B))*100
DBMS_OUTPUT.PUT_LINE(REC1.A ||'|'|| REC1.B ||'|'||VAR_PCT)
END LOOP;*
And the VAR_PCT is value for (VAR_X/SUM(REC1.B))*100
That's why I need calculate it inside the loop.

You can use window function sum(col) over () to find the overall total in the cursor definition itself. This is usually more performant then doing thing procedurally in a loop.
DECLARE
CURSOR C1 IS
SELECT A, B, 100 * b / sum(b) over () VAR_PCT FROM TBL;
BEGIN
FOR REC1 IN C1
LOOP
DBMS_OUTPUT.PUT_LINE(REC1.A ||'|'|| REC1.B ||'|'||REC1.VAR_PCT)
END LOOP;
END;
If the sum is for each A, then use partition by:
DECLARE
CURSOR C1 IS
SELECT A, B, 100 * b / sum(b) over (partition by A) VAR_PCT FROM TBL;
BEGIN
FOR REC1 IN C1
LOOP
DBMS_OUTPUT.PUT_LINE(REC1.A ||'|'|| REC1.B ||'|'||REC1.VAR_PCT)
END LOOP;
END;

Related

While loops with Strings not Integers

I'm having trouble finding any information on oracle plSQL while loops with strings online. All seem to be integer. When doing my research i feel i understand the integer aspect of while loops in plSQL but no sites that i have visited touched on or had examples of While Loops using strings.
For example: I can use a For loop to print individual letters from the word 'text' but what would stop me from using a While loop to get the same output?
DECLARE
c1 Number:= 1;
c2 Varchar2(4);
BEGIN
FOR c1 in 1..4
LOOP
SELECT substr('text' , c1 , 1 ) into c2 from dual;
dbms_output.put_line(c2);
END LOOP;
END;
If someone could explain how one would print a individual character or even the whole string with a while loop; or possibly point me in the right direction in terms of where to research example while loops with strings online.
Thank you.
You can write a WHILE loop entirely based on characters - no need for a counter of any kind. Something like this:
declare
txt varchar2(100);
begin
txt := 'my text';
while txt is not null loop
dbms_output.put_line(substr(txt, 1, 1)); -- or whatever else you need to do
txt := substr(txt, 2);
end loop;
end;
/
m
y
t
e
x
t
PL/SQL procedure successfully completed.
Yes, it can be written using a WHILE loop. The crucial thing is the length function and the counter. Also, you don't need a select query.
SET SERVEROUTPUT ON
DECLARE
c1 NUMBER := 1;
txt VARCHAR2(20) := 'text';
BEGIN
WHILE c1 <= length(txt) LOOP
dbms_output.put_line(substr(txt,c1,1));
c1 := c1 + 1; --increment the counter
END LOOP;
END;
/
Result
t
e
x
t
PL/SQL procedure successfully completed.
You can use SUBSTR in WHILE loop directly as follows:
SQL>
SQL> set serverout on
SQL> DECLARE
2 C1 NUMBER := 1;
3 C2 VARCHAR2(10) := 'TEXT';
4 BEGIN
5 WHILE SUBSTR(C2, C1, 1) IS NOT NULL LOOP
6 DBMS_OUTPUT.PUT_LINE(SUBSTR(C2, C1, 1));
7 C1 := C1 + 1;
8 END LOOP;
9 END;
10 /
T
E
X
T
PL/SQL procedure successfully completed.
SQL>
Cheers!!

Getting ORA-06532: Subscript outside of limit

I have created varray collection type inorder to get a serv_item_id column value from serv_item table. But while executing im getting subsript outside of limit error.
declare
type t1 is varray(1000) of serv_item%rowtype;
v_t1 t1:=t1();
n number :=0;
cursor c1 is select * from serv_item;
begin
open c1;
loop
v_t1.extend();
fetch c1 into v_t1(n);
exit when c1%notfound;
n:=n+1;
end loop;
close c1;
for i in 0..v_t1.count
loop
dbms_output.put_line('The serv item'||v_t1(i).serv_item_id);
end loop;
end;
/
varray indexing begins at 1, not 0.

why incremented value is coming as null after end of loop?

V_TOTAL_SIZE_MB values are coming within the loop but when I try to print V_TOTAL_SIZE_GB is coming as null after loop or inside the loop.
DECLARE
V_TOTAL_SIZE_MB NUMBER;
V_TOTAL_SIZE_GB NUMBER := 0.0;
CURSOR c1
IS
select NODE_ID from dept where id=12;
BEGIN
FOR c1_rec IN c1
LOOP
SELECT SUM(round(u.size/1024/1024,2))
INTO V_TOTAL_SIZE_MB
from child
WHERE =c1_rec.NODE_ID;
V_TOTAL_SIZE_GB := V_TOTAL_SIZE_GB+V_TOTAL_SIZE_MB;
dbms_output.put_line(':::V_TOTAL_SIZE_MB:'|| V_TOTAL_SIZE_MB);
END LOOP;
dbms_output.put_line(':::TOTAL_SIZE_GB:'|| V_TOTAL_SIZE_GB/1024);
END;

PL/SQL Nested Loops with cursors

I am working with Oracle PL/SQL. There are two cursors, namely c1 and c2.
v_temp VARCHAR(50);
For s1 IN c1
LOOP
--do something
FOR s2 IN c2
LOOP
--do something
v_temp := s1.s2.xxx; --PLS-00302: component 's2' must be declared
END LOOP;
END LOOP;
s2.xxx gives a column name, and with that column name I hope to assign the value of that column from s1 to v_temp.
For example:
In the first iteration, s2.xxx is 'column1',
I would like to assign s1.column1 to v_temp. In the second iteration, s2.xxx is 'column2', I would then like to assign s1.column2 to v_temp.
I got the error:
Error(191,48): PLS-00302: component 's2' must be declared
while trying to compile. I know that s1.s2.xxx is not valid, but is there another way of writing it that can make it work?
You need to fetch from a REF CURSOR and dynamically append the column_name to the select statement while opening the cursor. Here I am fetching all the column names from USER_TAB_COLUMNS for table EMPLOYEES and assigning their corresponding values to v_temp.
SET SERVEROUTPUT ON;
DECLARE
v_temp VARCHAR(50);
query1 VARCHAR2(1000);
c1 SYS_REFCURSOR;
CURSOR c2
IS
SELECT COLUMN_NAME xxx FROM USER_TAB_COLUMNS WHERE TABLE_NAME = 'EMPLOYEES';
BEGIN
FOR s2 IN c2
LOOP
--do something
query1 := 'SELECT ' ||s2.xxx||' FROM EMPLOYEES';
OPEN c1 FOR query1 ;
LOOP
FETCH c1 INTO v_temp;
DBMS_OUTPUT.PUT_LINE('COLUMN:'||s2.xxx||', VALUE:'|| v_temp);
EXIT
WHEN c1%NOTFOUND;
END LOOP;
CLOSE c1;
END LOOP;
END;
/
Since lengths of all the columns of Employees are < 50 , it is working Fine.The conversion happens implicitly for NUMBER and DATE data types.
Here is a sample Output.
COLUMN:EMPLOYEE_ID, VALUE:100
COLUMN:EMPLOYEE_ID, VALUE:101
COLUMN:EMPLOYEE_ID, VALUE:102
COLUMN:FIRST_NAME, VALUE:Eleni
COLUMN:FIRST_NAME, VALUE:Eleni
COLUMN:LAST_NAME, VALUE:Whalen
COLUMN:LAST_NAME, VALUE:Fay
COLUMN:HIRE_DATE, VALUE:17-06-03
COLUMN:HIRE_DATE, VALUE:21-09-05
I think you need smth like that:
declare
v_temp VARCHAR(50);
v_temp_1 VARCHAR(50);
cursor c2(p VARCHAR) is
SELECT *
FROM tbl
WHERE tbl.column = p;
begin
For s1 IN c1
LOOP
--do something
v_temp_1 := s1.xxx;
FOR s2 IN c2(v_temp_1)
LOOP
--do something
v_temp := s1.xxx;
END LOOP;
END LOOP;
end;

oracle cursor, concat with loop run figure

I want to use a cursor to loop through a management reporting chain using the Connect By Prior from Oracle. The order is then reversed so the VP is at the top and the record i started with is at the bottom (A.Corpid).
there's a cursor C1 on top that retrieves corpid following certain criteria
Each Canonical Name returned from that table (say f.i it has 6 rows) i want to store in defined TIER1,TIER2, TIER3 variables.
Somehow i can't figure out how to combine the word 'TIER' with the row number i
DECLARE
cursor c1 is
select distinct corpid, cn from Mytable where Country ='ITA';
master varchar2(50);
Tier1 varchar2(50);
Tier2 varchar2(50);
Tier3 varchar2(50);
Tier4 varchar2(50);
Tier5 varchar2(50);
Tier6 varchar2(50);
Tier7 varchar2(50);
Tier8 varchar2(50);
Begin
for rec in c1
loop
dbms_output.put_line(rec.cn);
DECLARE
Cursor C2 is
SELECT CN FROM Mytable A CONNECT BY PRIOR A.reportsto=A.corpid
START WITH A.corpid=rec.corpid
order by rownum desc;
Begin
open C2;
for i in 1..8 loop
fetch C2 into master;
dbms_output.put_line(master);
'Tier'||to_char(i)) :=master ;
end loop;
end;
if TIER1 is null then
TIER1:='';
end if;
*/ remmed out until the variable assignments work */
-- update mytable set VP_TIER1=TIER1 where corpid=rec.corpid;
end loop;
end;
Oracle complains about the '||'
(ORA-06550: line 33, column 31:
PLS-00103: Encountered the symbol "|" when expecting one of the following:
:= . ( # % ;
)
I've tried as well to concat but that didn't work either
ORA-06550: line 33, column 26:
PLS-00306: wrong number or types of arguments in call to 'CONCAT'
Your concatenation of the literal and variable aren't going to evaluate to the variable TIER1 like you are hoping. Try using arrays instead:
DECLARE
cursor c1
is
select distinct corpid, cn
from Mytable where Country ='ITA';
master varchar2(50);
TYPE Tier_arr_t IS TABLE OF VARCHAR2(50) INDEX BY PLS_INTEGER;
Tier_arr TIER_ARR_T;
Begin
for rec in c1
loop
dbms_output.put_line(rec.cn);
DECLARE
Cursor C2
is
SELECT CN
FROM Mytable A
CONNECT BY PRIOR A.reportsto=A.corpid
START WITH A.corpid=rec.corpid
order by rownum desc;
Begin
open C2;
for i in 1..8
loop
fetch C2 into master;
dbms_output.put_line(master);
Tier_arr(i) :=master ;
end loop;
end;
if TIER1 is null
then
TIER1:='';
end if;
update mytable set VP_TIER1=Tier_arr(1), VP_TIER2=Tier_arr(2) where corpid=rec.corpid;
end loop;
end;
There is also probably a more set-based approach to doing this which would be much preferred, but this should work if it is just a one-time need.

Resources