Looping in PL/SQL variable is not a cursor - oracle

I'm trying to run the following loop:
DECLARE
v_banknumber varchar2(9) := '123456789';
v_counter number := 9;
v_result number;
begin
for i in v_banknumber
loop
v_result := v_counter * TO_NUMBER(i) + v_result;
v_counter := v_counter - 1;
end loop;
end;
I'm getting a error at line 2:
Error report -
ORA-06550: line 6, column 10:
PLS-00456: item 'V_BANKNUMBER' is not a cursor
ORA-06550: line 6, column 1:
PL/SQL: Statement ignored
06550. 00000 - "line %s, column %s:\n%s"
*Cause: Usually a PL/SQL compilation error.
*Action:
If I read this well, it seems like it should work. Anyone here that can explain me why it's not working?
The first digit must be multiplied by 9, the second with 8, the third with 7, and so on and save the sum of it in a result variable.

At a guess, what you want to do is
DECLARE
v_banknumber varchar2(9) := '123456789';
v_counter number := 9;
v_result number := 0;
begin
for i in 1..LENGTH(v_banknumber)
loop
v_result := v_counter * TO_NUMBER(SUBSTR(v_banknumber, i, 1)) + v_result;
v_counter := v_counter - 1;
end loop;
end;
This gives a result of 165.
Best of luck.
EDIT
Or you could really use a cursor:
DECLARE
v_banknumber varchar2(9) := '123456789';
v_counter number := 9;
v_result number := 0;
begin
for aRow in (SELECT LEVEL AS I FROM DUAL CONNECT BY LEVEL <= LENGTH(v_banknumber))
loop
v_result := v_counter * TO_NUMBER(SUBSTR(v_banknumber, aRow.I, 1)) + v_result;
v_counter := v_counter - 1;
end loop;
end;
Produces 165 as the result.
EDIT #2
Or, because there's no kill like overkill, you could just do it all in SQL:
WITH cteBank_number AS (SELECT '123456789' AS BANK_NUMBER FROM DUAL),
cteI AS (SELECT LEVEL AS I
FROM DUAL d
CROSS JOIN cteBank_number b
CONNECT BY LEVEL <= LENGTH(b.BANK_NUMBER)),
cteNums AS (SELECT TO_NUMBER(SUBSTR(b.BANK_NUMBER, LENGTH(b.BANK_NUMBER)-i.I+1, 1)) AS DIGIT,
i.I AS I,
TO_NUMBER(SUBSTR(b.BANK_NUMBER, LENGTH(b.BANK_NUMBER)-i.I+1, 1)) * i.I AS NUM
FROM cteBank_number b
CROSS JOIN cteI i)
SELECT SUM(NUM)
FROM cteNums n;
Still produces 165 as the result.

Your v_banknumber variable is a string not a cursor. You need to loop over each character in that string, and treat that character as a digit.
You could do this as:
set serveroutput on
declare
v_banknumber varchar2(9) := '123456789';
v_result number := 0;
begin
for v_counter in reverse 1..length(v_banknumber)
loop
v_result := v_result
+ (v_counter * to_number(substr(v_banknumber, -v_counter, 1)));
end loop;
dbms_output.put_line('The result is: ' || v_result);
end;
/
The result is: 165
PL/SQL procedure successfully completed.
With extra debugs to try to show what is happening on each iteration:
declare
v_banknumber varchar2(9) := '123456789';
v_result number := 0;
begin
dbms_output.put_line('length(v_banknumber) is: ' || length(v_banknumber));
for v_counter in reverse 1..length(v_banknumber)
loop
dbms_output.put_line('v_counter is: ' || v_counter);
dbms_output.put_line(' Digit is substr(v_banknumber, v_counter, 1): '
|| substr(v_banknumber, -v_counter, 1));
dbms_output.put_line(' Calculation for digit is: '
|| v_counter * to_number(substr(v_banknumber, -v_counter, 1)));
v_result := v_result
+ (v_counter * to_number(substr(v_banknumber, -v_counter, 1)));
dbms_output.put_line(' Running total: ' || v_result);
end loop;
dbms_output.put_line('The result is: ' || v_result);
end;
/
length(v_banknumber) is: 9
v_counter is: 9
Digit is substr(v_banknumber, v_counter, 1): 1
Calculation for digit is: 9
Running total: 9
v_counter is: 8
Digit is substr(v_banknumber, v_counter, 1): 2
Calculation for digit is: 16
Running total: 25
v_counter is: 7
Digit is substr(v_banknumber, v_counter, 1): 3
Calculation for digit is: 21
Running total: 46
v_counter is: 6
Digit is substr(v_banknumber, v_counter, 1): 4
Calculation for digit is: 24
Running total: 70
v_counter is: 5
Digit is substr(v_banknumber, v_counter, 1): 5
Calculation for digit is: 25
Running total: 95
v_counter is: 4
Digit is substr(v_banknumber, v_counter, 1): 6
Calculation for digit is: 24
Running total: 119
v_counter is: 3
Digit is substr(v_banknumber, v_counter, 1): 7
Calculation for digit is: 21
Running total: 140
v_counter is: 2
Digit is substr(v_banknumber, v_counter, 1): 8
Calculation for digit is: 16
Running total: 156
v_counter is: 1
Digit is substr(v_banknumber, v_counter, 1): 9
Calculation for digit is: 9
Running total: 165
The result is: 165

Did you mean to do it as an array?
DECLARE
type array_t is varray(9) of number;
a_banknumber array_t := array_t (1,2,3,4,5,6,7,8,9);
v_counter number := a_banknumber.count;
v_result number := 0;
begin
for i in 1..a_banknumber.count
loop
v_result := v_counter * a_banknumber(i) + v_result;
v_counter := v_counter - 1;
end loop;
dbms_output.put_line('Result: ' || v_result);
end;

Related

PLS-00103: Encountered the symbol "+" when expecting one of the following: (

declare
i number;
sum number;
begin
i:=1;
sum:=0;
for i in 1..100 loop
if MOD(i,2) != 0 then
sum:= sum + i;
dbms_output.put_line(i);
end if;
end loop;
dbms_output.Put_line(sum);
end;
sum is a reserved word, reserved for built-in function. Rename variable to v_sum (for example).
SQL> set serveroutput on
SQL>
SQL> DECLARE
2 v_sum NUMBER;
3 BEGIN
4 v_sum := 0;
5 FOR i IN 1 .. 100 LOOP
6 IF MOD (i, 2) != 0 THEN
7 v_sum := v_sum + i;
8 -- DBMS_OUTPUT.put_line (i);
9 END IF;
10 END LOOP;
11 DBMS_OUTPUT.Put_line (v_sum);
12 END;
13 /
2500
PL/SQL procedure successfully completed.
SQL>

This seems ok ,please correct me

n number := &n;
c number;
i number;
function isprime(x in number)
RETURN number
IS
begin
count number:=0;
for i in 2..x/2 loop
if mod(x,i)=0 then
count := count+1;
end if;
end loop;
return count;
end;
begin
c:=isprime(n);
if c=0 then
dbms_output.put_line(n||'is a prime number');
else
dbms_output.put_line(n||'is not prime');
end if;
end;
/
ORA-06550: line 11, column 7:
PLS-00103: Encountered the symbol "NUMBER" when expecting one of the following:
:= . ( # % ;
The symbol "." was substituted for "NUMBER" to continue.
Don't use column names that match Oracle's built-in functions (count is one of them). Declare variables in declaration section, not just anywhere.
SQL> DECLARE
2 n NUMBER := &par_n;
3 c NUMBER;
4 i NUMBER;
5
6 FUNCTION isprime (x IN NUMBER)
7 RETURN NUMBER
8 IS
9 l_count NUMBER := 0;
10 BEGIN
11 FOR i IN 2 .. x / 2
12 LOOP
13 IF MOD (x, i) = 0
14 THEN
15 l_count := l_count + 1;
16 END IF;
17 END LOOP;
18
19 RETURN l_count;
20 END;
21 BEGIN
22 c := isprime (n);
23
24 IF c = 0
25 THEN
26 DBMS_OUTPUT.put_line (n || ' is a prime number');
27 ELSE
28 DBMS_OUTPUT.put_line (n || ' is not prime');
29 END IF;
30 END;
31 /
Enter value for par_n: 6
6 is not prime
PL/SQL procedure successfully completed.
SQL> /
Enter value for par_n: 7
7 is a prime number
PL/SQL procedure successfully completed.
SQL>

Write PL/SQL code to generate Armstrong number from 1 to 500

I am getting output as a = 1. I have taken a for loop from 1 to 500 and while loops inside the outer for loop.
declare
n number;
s number:=0;
r number;
len number;
m number;
begin
for a in 1..500 loop
m:=a;
n:=a;
len:=length(to_char(n));
while(n>0) loop
r:=mod(n,10);
s:=s+power(r,len);
n:=trunc(n/10);
end loop;
if m=s then
dbms_output.put_line('a='||to_char(a)');
end if;
end loop;
end;
How about this?
substr splits i to 3 separate digits
nvl is here to avoid adding null value if those digits don't exist (yet)
power function calculates i's cube
display i if it is equal to r (as "result")
SQL> declare
2 r number;
3 begin
4 for i in 1 .. 500 loop
5 r := power(to_number(substr(to_char(i), 1, 1)), 3) +
6 nvl(power(to_number(substr(to_char(i), 2, 1)), 3), 0) +
7 nvl(power(to_number(substr(to_char(i), 3, 1)), 3), 0);
8
9 if r = i then
10 dbms_output.put_line(i);
11 end if;
12 end loop;
13 end;
14 /
1
153
370
371
407
PL/SQL procedure successfully completed.
SQL>
You never reset s and you do not need the final IF statement (unless you are only interested in the Armstrong numbers which equal the original number):
declare
n number;
s number:=0;
r number;
len number;
m number;
begin
for a in 1..500 loop
m:=a;
n:=a;
s:=0; -- Reset s for each loop
len:=length(to_char(n));
while(n>0) loop
r:=mod(n,10);
s:=s+power(r,len);
n:=trunc(n/10);
end loop;
dbms_output.put_line(a || '=' || s); -- Output values for every loop.
end loop;
end;
/
db<>fiddle here

PL/SQL function returns minimal number

How to write a simple function that returns minimal salary. IN parameters are salary1,salary2,salary3 (9240, 9750, 8320) and it is forbidden to use finished functions.
I have no code whatsoever. I am very new at this and am trying to learn something.
The function is already exists in PLSQL. Check it out here. There are good examples of how to use it
UPD: As per Pavel mentioned here is a pair of examples
SQL:
select least(100, 1, 200) from dual; -- returns 1
PLSQL:
create or replace procedure get_min(s1 number, s2 number, s3 number)
is
min_sal number := 0;
begin
min_sal := least(s1, s2, s3);
dbms_output.put_line('min: ' || min_sal);
end;
if it is not allowed to use existing functions, you can do it using If then else
create or replace function get_min(s1 number, s2 number, s3 number)
return number
is
min_sal number := 0;
begin
---------------------
-- if the first value is less than the second value
-- , then the first value is the min of both values
-- otherwise the second value is min
if s1 < s2 then
min_sal := s1;
else
min_sal := s2;
end if;
------------------------------------
-- now you check the new min value against the third value.
if s3 < min_sal then
min_sal := s3;
end if;
dbms_output.put_line('min: ' || min_sal);
return min_sal;
end;
/
DECLARE
v_result NUMBER;
BEGIN
v_result := GET_MIN(1, 1, 1);
v_result := GET_MIN(2, 1, 1);
v_result := GET_MIN(1, 2, 1);
v_result := GET_MIN(1, 1, 2);
v_result := GET_MIN(2, 2, 1);
v_result := GET_MIN(1, 2, 2);
v_result := GET_MIN(1, 2, 3);
v_result := GET_MIN(2, 1, 3);
v_result := GET_MIN(3, 2, 1);
END;
/
Result:
dbms_output:
min: 1
min: 1
min: 1
min: 1
min: 1
min: 1
min: 1
min: 1
min: 1
db<>fiddle here

increment function in plsql varchar2

I want use this in a varchar2. Ex.:
declare
num number := &Number;
serie varchar2(200) := 'S = ';
begin
for x in 1 .. num loop
serie += x, ' + ';
end loop; `
end;
/
In the end I want that the serie be like "S = 1 + 2 + 3 ..." How can i make that work?
That would be something like this:
SQL> set serveroutput on
SQL> declare
2 num number := &Number;
3 serie varchar2(200) := 'S = ';
4 begin
5 for x in 1 .. num loop
6 serie := serie || to_char(x) || ' + ';
7 end loop;
8
9 -- remove the trailing "+"
10 serie := rtrim(serie, ' +');
11 dbms_output.put_Line(serie);
12 end;
13 /
Enter value for number: 5
S = 1 + 2 + 3 + 4 + 5
PL/SQL procedure successfully completed.
SQL>
A few comments:
line 6: you have to concatenate (concatenation operator is a double pipe sign, ||) previous value of SERIE; otherwise, you'd have only the last number in it
line 10: remove the trailing "+" sign
What could be done in pure SQL, usually should be done in pure SQL:
declare
num number := &Number;
serie varchar2(200);
begin
select 'S = ' || listagg(rownum, ', ') within group (order by rownum)
into serie
from dual
connect by level <= num;
dbms_output.put_line(serie);
end;
/
The result for num = 10:
S = 1, 2, 3, 4, 5, 6, 7, 8, 9, 10
Note, listagg function was introduced in Oracle version 11.2.

Resources