increment function in plsql varchar2 - oracle

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.

Related

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

Print the sum of even digits of a number in Pl/sql

I cant seem to resolve this issue
As of the error itself, it is because you're trying to put the whole row (temp, which is declared as a cursor variable - c_nm%rowtype) into an integer variable (i). It won't work, although temp actually contains only one column - num.
So, line #15 on your screenshot:
No : i := temp;
Yes: i := temp.num;
Once you fix it, your code works but - unfortunately, produces wrong result. In input number 121974553, even digits are 2, 9, 4 and 5 whose sum equals 20, not 6 (as your result suggests):
SQL> set serveroutput on;
SQL> declare
2 ad int := 0;
3 i int;
4 b int;
5 cursor c_nm is select * From numb;
6 temp c_nm%rowtype;
7 begin
8 open c_nm;
9 loop
10 fetch c_nm into temp;
11 exit when c_nm%notfound;
12 i := temp.num; --> this
13
14 while i > 0 loop
15 b := mod(i, 10);
16 if mod(b, 2) = 0 then
17 ad := b + ad;
18 end if;
19 i := trunc(i/10);
20 end loop;
21 end loop;
22 dbms_output.put_line('ad = ' ||ad);
23 close c_nm;
24 end;
25 /
ad = 6
PL/SQL procedure successfully completed.
SQL>
A simpler option might be this: split number into digits (each in its separate row) so that you could apply SUM function to its even digits:
SQL> select * from numb;
NUM
----------
121974553 --> sum of even digits = 2 + 9 + 4 + 5 = 20
253412648 --> = 5 + 4 + 2 + 4 = 15
SQL> with
2 split as
3 -- split number into rows
4 (select num,
5 substr(num, column_value, 1) digit,
6 case when mod(column_value, 2) = 0 then 'Y'
7 else 'N'
8 end cb_odd_even
9 from numb cross join table(cast(multiset(select level from dual
10 connect by level <= length(num)
11 ) as sys.odcinumberlist))
12 )
13 -- final result: summary of digits in even rows
14 select num,
15 sum(digit)
16 from split
17 where cb_odd_even = 'Y'
18 group by num;
NUM SUM(DIGIT)
---------- ----------
253412648 15
121974553 20
SQL>
If it must be PL/SQL, slightly rewrite it as
SQL> declare
2 result number;
3 begin
4 for cur_r in (select num from numb) loop
5 with
6 split as
7 -- split number into rows
8 (select substr(cur_r.num, level, 1) digit,
9 case when mod(level, 2) = 0 then 'Y'
10 else 'N'
11 end cb_odd_even
12 from dual
13 connect by level <= length(cur_r.num)
14 )
15 -- final result: summary of digits in even rows
16 select sum(digit)
17 into result
18 from split
19 where cb_odd_even = 'Y';
20
21 dbms_output.put_line(cur_r.num || ' --> ' || result);
22 end loop;
23 end;
24 /
121974553 --> 20
253412648 --> 15
PL/SQL procedure successfully completed.
SQL>
You could do something like this. A few things of note: first, you can use an implicit cursor (the for rec in (select ...) loop construct). You don't need to declare the data type of rec, you don't need to open the cursor - and then remember to close it when you are finished - etc. Implicit cursors are a great convenience, best to learn about it as early as possible. Second, note that rec (in my notation) is just a pointer; to access the value from it, you must reference the table column (as in, rec.num) - Littlefoot has already shown that in his reply. Third, a logic mistake in your attempt: if the table has more than one row, you must initialize ad to 0 for each new value - you can't just initialize it to 0 once, at the beginning of the program.
So, with all that said - here is some sample data, then the procedure and its output.
create table numb (num int);
insert into numb values(121975443);
insert into numb values(100030000);
insert into numb values(null);
insert into numb values(113313311);
insert into numb values(2020);
commit;
. . . . .
declare
ad int;
i int;
begin
for rec in (select num from numb) loop
ad := 0;
i := rec.num;
while i > 0 loop
if mod(i, 2) = 0 then
ad := ad + mod(i, 10);
end if;
i := trunc(i/10);
end loop;
dbms_output.put_line('num: ' || nvl(to_char(rec.num), 'null') ||
' sum of even digits: ' || ad);
end loop;
end;
/
num: 121975443 sum of even digits: 10
num: 100030000 sum of even digits: 0
num: null sum of even digits: 0
num: 113313311 sum of even digits: 0
num: 2020 sum of even digits: 4
PL/SQL procedure successfully completed.

Generating random numbers within a specified range

I want to create 10 pairs of random integers within the range of [-4,+4) using PLSQL and then using the pair to solve a primary equation(num1*X+num2=0) and save the results inside the table, as well as a text output of what the type of outcome for the equation(Solvable/Indefinite/Impossible). I am using Oracle LiveSQL.
I used cursor to make sure the randomized number is an integer.
CURSOR NUMcursor1 IS
SELECT ROUND(DBMS_RANDOM.VALUE(-4,+4),0) FROM DUAL;
num1 EquatA2.dat1%TYPE; num2 EquatA2.dat2%TYPE;
solution EquatA2.sol%TYPE; notes EquatA2.note%TYPE;
`
`
CREATE TABLE EquatA2
(
dat1 NUMBER(2,0),
dat2 NUMBER(2,0),
sol NUMBER(6,3),
note VARCHAR2(20)
)
DECLARE
num1 EquatA2.dat1%TYPE; num2 EquatA2.dat2%TYPE;
solution EquatA2.sol%TYPE; notes EquatA2.note%TYPE;
i INT; i:=1;
CURSOR NUMcursor1 IS
SELECT ROUND(DBMS_RANDOM.VALUE(-4,+4),0) FROM DUAL;
CURSOR NUMcursor2 IS
SELECT ROUND(DBMS_RANDOM.VALUE(-4,+4),0) FROM DUAL;
BEGIN
OPEN NUMcursor1;
OPEN NUMcursor2;
FOR i IN 1..10
LOOP
FETCH NUMcursor1 INTO num1;
EXIT WHEN NUMcursor1%NOTFOUND;
FETCH NUMcursor2 INTO num2;
EXIT WHEN NUMcursor2%NOTFOUND;
DBMS_OUTPUT.PUT_LINE(num1);
DBMS_OUTPUT.PUT_LINE(num2);
IF (num1 != 0) THEN solution := -num2 / num1 AND notes := 'solvable';
ELSIF (num1 == 0 AND num2 == 0) THEN notes := 'indefinite';
ELSIF (num1 == 0 AND num2 != 0) THEN notes := 'impossible';
END IF;
INSERT INTO EquatA2 VALUES(num1,num2,solution,notes);
END LOOP;
END;
`
`
Expected results: 10 text outputs and the range of the random numbers to be [-4,+4)
Actual results(errors):
ORA-00922: missing or invalid option
Invalid statement
Unsupported Command
Invalid statement
Result Set 6
ROUND(DBMS_RANDOM.VALUE(-4,+4),0)
-2
Download CSV
Invalid statement
Result Set 7
ROUND(DBMS_RANDOM.VALUE(-4,+4),0)
-3
Download CSV
ORA-06550: line 18, column 56: PLS-00103: Encountered the symbol "=" when expecting one of the following: . ( * # % & = - + ; < / > at in is mod remainder not rem <an exponent (**)> <> or != or ~= >= <= <> and or like like2 like4 likec between || multiset member submultiset The symbol "* was inserted before "=" to continue.
I've modified your code so that it works. Here you go.
Table:
SQL> CREATE TABLE EquatA2
2 (
3 dat1 NUMBER(2,0),
4 dat2 NUMBER(2,0),
5 sol NUMBER(6,3),
6 note VARCHAR2(20)
7 );
Table created.
SQL>
PL/SQL anonymous procedure:
SQL> DECLARE
2 num1 EquatA2.dat1%TYPE;
3 num2 EquatA2.dat2%TYPE;
4 solution EquatA2.sol%TYPE;
5 notes EquatA2.note%TYPE;
6 BEGIN
7 delete from equata2;
8 FOR i IN 1..10 LOOP
9 num1 := ROUND(DBMS_RANDOM.VALUE(-4, +4), 0);
10 num2 := ROUND(DBMS_RANDOM.VALUE(-4, +4), 0);
11 -- DBMS_OUTPUT.PUT_LINE(num1);
12 -- DBMS_OUTPUT.PUT_LINE(num2);
13
14 IF num1 != 0 THEN
15 solution := -num2 / num1;
16 notes := 'solvable';
17 ELSIF num1 = 0 AND num2 = 0 THEN
18 notes := 'indefinite';
19 ELSIF num1 = 0 AND num2 != 0
20 THEN notes := 'impossible';
21 END IF;
22
23 INSERT INTO EquatA2 VALUES (num1, num2, solution, notes);
24 END LOOP;
25 END;
26 /
PL/SQL procedure successfully completed.
Result:
SQL> select * from equata2;
DAT1 DAT2 SOL NOTE
---------- ---------- ---------- --------------------
1 -4 4 solvable
-1 0 0 solvable
0 3 0 impossible
0 2 0 impossible
0 0 0 indefinite
3 -1 ,333 solvable
4 3 -,75 solvable
1 -1 1 solvable
-1 -2 -2 solvable
2 3 -1,5 solvable
10 rows selected.
SQL>

Looping in PL/SQL variable is not a cursor

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;

Resources