Generating random numbers within a specified range - oracle

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>

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>

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.

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.

Need Luhn Modulus 16 coding example to generate a check digit in PL/SQL

Does anyone have a working function available to use within Oracle using PL/SQL which implements the Luhn Mod 16 Algorithm to generate a check digit for an input code number such as the following example? 0B012722900021AC35B2
LOGIC
Map from HEX into Decimal equivalent 0 B 0 1 2 7 2 2 9 0 0 0 2 1 A C 3 5 B 2 - becomes 0 11 0 1 2 7 2 2 9 0 0 0 2 1 10 12 3 5 11 2
Start with the last character in the string and move left doubling every other number -
Becomes 0 22 0 2 2 14 2 4 9 0 0 0 2 2 10 24 3 10 11 4
Convert the "double" to a Base 16 (Hexadecimal) format. If the conversion results in numeric output, retain the value.
Becomes: 0 16 0 2 2 E 2 4 9 0 0 0 2 2 10 18 3 A 11 4
Reduce by splitting down any resultant values over a single digit in length.
Becomes 0 (1+6) 0 2 2 E 2 4 9 0 0 0 2 2 10 (1+8) 3 A 11 4
Sum all digits. Apply the last numeric value returned from the previous sequence of calculations (if the current value is A-F substitute the numeric value from step 1)
Becomes 0 7 0 2 2 7 2 4 9 0 0 0 2 2 10 9 3 5 11 4
The sum of al l digits is 79 (0+7+0+2+2+7+2+4+9+0+0+0+2+2+10+9+3+5+11+4)
Calculate the value needed to obtain the next multiple of 16, in this case the next multiple 16 is 80 therefore the value is 1
The associated check character is 1
Thanks Lee
How about this?
CREATE OR REPLACE TYPE VARCHAR_TABLE_TYPE AS TABLE OF VARCHAR2(1000);
DECLARE
luhn VARCHAR2(100) := '0B012722900021AC35B2';
digits VARCHAR_TABLE_TYPE;
DigitSum INTEGER;
BEGIN
SELECT REGEXP_SUBSTR(luhn, '.', 1, LEVEL)
BULK COLLECT INTO digits
FROM dual
CONNECT BY REGEXP_SUBSTR(luhn, '.', 1, LEVEL) IS NOT NULL;
FOR i IN digits.FIRST..digits.LAST LOOP
digits(i) := TO_NUMBER(digits(i), 'X'); -- Map from HEX into Decimal equivalent
IF digits.COUNT MOD 2 = i MOD 2 THEN -- every second digit from left
digits(i) := 2 * TO_NUMBER(digits(i)); -- doubling number
digits(i) := TO_CHAR(digits(i), 'fmXX'); -- Convert the "double" to a Base 16 (Hexadecimal) format
IF (REGEXP_LIKE(digits(i), '^\d+$')) THEN
-- Reduce by splitting down any resultant values over a single digit in length.
SELECT SUM(REGEXP_SUBSTR(digits(i), '\d', 1, LEVEL))
INTO digits(i)
FROM dual
CONNECT BY REGEXP_SUBSTR(digits(i), '\d', 1, LEVEL) IS NOT NULL;
END IF;
END IF;
END LOOP;
FOR i IN digits.FIRST..digits.LAST LOOP
-- I don't understand step 5), let's simulate it
IF digits(i) = 'E' THEN digits(i) := 7; END IF;
IF digits(i) = 'A' THEN digits(i) := 5; END IF;
END LOOP;
-- The sum of all digits
SELECT SUM(COLUMN_VALUE)
INTO DigitSum
FROM TABLE(digits);
-- Calculate the value needed to obtain the next multiple of 16
DBMS_OUTPUT.PUT_LINE ( 16 - DigitSum MOD 16 );
END;
Here is a function which implements the steps you outlined in your question:
create or replace function get_luhn_16_check_digit
( p_str in varchar)
return pls_integer
is
b16 sys.dbms_debug_vc2coll := sys.dbms_debug_vc2coll() ;
n16 sys.odcinumberlist := sys.odcinumberlist();
tot simple_integer := 0;
chk_digit pls_integer;
begin
-- step 1)
select to_number(tkn, 'X')
bulk collect into n16
from ( select substr(p_str, level, 1) as tkn
from dual
connect by level <= length(p_str));
b16.extend(n16.count());
for idx in 1..n16.count() loop
if mod(idx, 2) = 0
then
-- step 2) and 3)
b16(idx) := to_char( to_char(n16(idx)) * 2, 'fmXX');
-- step 4)
if length( b16(idx)) = 2 then
b16(idx) := to_number(substr(b16(idx),1,1)) + to_number(substr(b16(idx),2,1));
end if;
else
b16(idx) := trim(to_char(n16(idx)));
end if;
end loop;
-- step 5) and 6)
for idx in 1..b16.count() loop
if b16(idx) not in ('A','B','C','D','E','F') then
tot := tot + to_number(b16(idx));
else
tot := tot + n16(idx);
end if;
end loop;
-- step 7) and 8)
chk_digit := (ceil(tot/16)*16) - tot;
return chk_digit;
end;
/
To run:
select get_luhn_16_check_digit('0B012722900021AC35B2') from dual;
This now returns 1. Here is a LiveSQL demo.
There is still the question of what happens when the modulus 16 is greater than 9; for instance, this value returns 15.
select get_luhn_16_check_digit('22111111111111111111') from dual;
A decimal result such as 15 is obviously not a check digit, which suggests you need an additional step 9). Perhaps we need to convert 15 -> (1+5) -> 6. Or Perhaps the digit should be base16? Please edit your question to confirm the appropriate rule.

Taking user input 'n' times PL/SQL

I want to write a PL/SQL program that takes user input 'n' times. Here n is 10, but this only takes input 1 time and displays that input value 10 times as the loop is from 1 to 10. How can I write a program that takes 'n' input values and display them.
set serveroutput on;
DECALRE
num NUMBER(10);
BEGIN
for i in 1..10
loop
dbms_output.put_line(&num);
END loop;
END;
/
set serveroutput on;
DECALRE
num NUMBER(10) := &num;
BEGIN
for i in 1..10
loop
dbms_output.put_line(num);
END loop;
END;
/
PL/SQL is not an interactive language. It is SQL*Plus that is prompting you for a value and it needs to get all the substitution values it needs before it can send the PL/SQL block to the database to be executed.
So, there is no way for PL/SQL to prompt the user for input in loop.
Reading through the comments:
task given to me was :- "insert 10 records into a table using loop -
pl/sql"
and
so if there were 5 columns in a table, do i have to use 50 variables
for insertion ?
Answer to your above question is NO if you want the same set of records to be inserted to your table 10 times. Below is the way you can do it. When you execute the block, it will ask you to promt value for 5 columns and accordingly it would insert 10 set of records with the same value to the table. See below.
SQL> DECLARE
num1 NUMBER (10) := &num1;
num2 NUMBER (10) := &num2;
num3 NUMBER (10) := &num3;
num4 NUMBER (10) := &num4;
num5 NUMBER (10) := &num5;
BEGIN
FOR i IN 1 .. 10
LOOP
INSERT INTO TAB (col1,
col2,
col3,
col4,
col5)
VALUES (num1,
num2,
num3,
num4,
num5);
END LOOP;
COMMIT;
END;
/
Enter value for num1: 1
old 2: num1 NUMBER (10) := &num1;
new 2: num1 NUMBER (10) := 1;
Enter value for num2: 2
old 3: num2 NUMBER (10) := &num2;
new 3: num2 NUMBER (10) := 2;
Enter value for num3: 3
old 4: num3 NUMBER (10) := &num3;
new 4: num3 NUMBER (10) := 3;
Enter value for num4: 4
old 5: num4 NUMBER (10) := &num4;
new 5: num4 NUMBER (10) := 4;
Enter value for num5: 5
old 6: num5 NUMBER (10) := &num5;
new 6: num5 NUMBER (10) := 5;
PL/SQL procedure successfully completed.
OUTPUT:
SQL> select * from tab;
COL1 COL2 COL3 COL4 COL5
---------- ---------- ---------- ---------- ----------
1 2 3 4 5
1 2 3 4 5
1 2 3 4 5
1 2 3 4 5
1 2 3 4 5
1 2 3 4 5
1 2 3 4 5
1 2 3 4 5
1 2 3 4 5
1 2 3 4 5
10 rows selected.

Resources