Is it possible to write function and procedure within single program in PL/SQL without using packages? - oracle

I'm trying to calculate LCM using GCF but somehow i'm getting error saying "no function with name LCM exists in the scope". What can i do about this?. I think this error is because i'm writing procedure and function together..
create or replace FUNCTION gcf (
x IN INTEGER,
y IN INTEGER
) RETURN INTEGER IS
res INTEGER;
BEGIN
IF ( y = 0 ) OR MOD(y,x) = 0 THEN
RETURN x;
ELSIF ( x = 0 ) THEN
RETURN y;
ELSIF ( x < y ) THEN
res := gcf(y,x);
ELSE
res := gcf(y,MOD(x,y) );
END IF;
RETURN res;
END;
/
create or replace PROCEDURE lcm (
num1 IN INTEGER,
num2 IN INTEGER,
answer OUT INTEGER
) IS
BEGIN
IF num1 = 0 AND num2 = 0 THEN
answer := 0;
ELSE
answer := abs(num1 * num2) / gcf(num1,num2);
END IF;
END lcm;
/
DECLARE
c integer;
BEGIN
dbms_output.put_line(' LCM(8, 12)-> ' || lcm(8, 12,c) );
dbms_output.put_line(' LCM(38,150)-> ' || lcm(38,150,c) );
dbms_output.put_line(' LCM(16,50)-> ' || lcm(16,60,c) );
dbms_output.put_line(' LCM(16,60)-> ' || lcm(16,60,c) );
dbms_output.put_line(' LCM(48,99)-> ' || lcm(48,99,c) );
END;
/

You can't use a PL/SQL procedure like a function. You must simply run it without being part of any other expression, which will set the value of the out parameter c.
DECLARE
c integer;
BEGIN
lcm(8, 12,c);
dbms_output.put_line(' LCM(8, 12)-> ' || c);
lcm(38,150,c);
dbms_output.put_line(' LCM(38,150)->' || c);
lcm(16,60,c);
dbms_output.put_line(' LCM(16,50)-> ' || c);
lcm(16,60,c);
dbms_output.put_line(' LCM(16,60)-> ' || c);
lcm(48,99,c);
dbms_output.put_line(' LCM(48,99)-> ' || c );
END;
/

Create the procedure and function inside the procedure as follows:
create or replace PROCEDURE lcm (
num1 IN INTEGER,
num2 IN INTEGER,
answer OUT INTEGER
) IS
FUNCTION gcf (
x IN INTEGER,
y IN INTEGER
) RETURN INTEGER IS
res INTEGER;
BEGIN
IF ( y = 0 ) OR MOD(y,x) = 0 THEN
RETURN x;
ELSIF ( x = 0 ) THEN
RETURN y;
ELSIF ( x < y ) THEN
res := gcf(y,x);
ELSE
res := gcf(y,MOD(x,y) );
END IF;
RETURN res;
END;
BEGIN
IF num1 = 0 AND num2 = 0 THEN
answer := 0;
ELSE
answer := abs(num1 * num2) / gcf(num1,num2);
END IF;
END lcm;
/
Then call it:
DECLARE
c INTEGER;
BEGIN
lcm (8, 12, c);
DBMS_OUTPUT.put_line (' LCM(8, 12)-> ' || c);
lcm (38, 150, c);
DBMS_OUTPUT.put_line (' LCM(38,150)-> ' || c);
lcm (16, 60, c);
DBMS_OUTPUT.put_line (' LCM(16,50)-> ' || c);
lcm (16, 60, c);
DBMS_OUTPUT.put_line (' LCM(16,60)-> ' || c);
lcm (48, 99, c);
DBMS_OUTPUT.put_line (' LCM(48,99)-> ' || c);
END;

The Lowest Common Multiple should be a function (since it returns a single value):
CREATE FUNCTION lcm (
num1 IN INTEGER,
num2 IN INTEGER,
) RETURN INTEGER DETERMINISTIC
IS
BEGIN
IF num1 = 0 AND num2 = 0 THEN
RETURN 0;
END IF;
RETURN abs(num1 * num2) / gcf(num1,num2);
END lcm;
/
Then you can use the code:
BEGIN
dbms_output.put_line(' LCM(8, 12)-> ' || lcm(8, 12) );
dbms_output.put_line(' LCM(38,150)-> ' || lcm(38,150) );
dbms_output.put_line(' LCM(16,50)-> ' || lcm(16,60) );
dbms_output.put_line(' LCM(16,60)-> ' || lcm(16,60) );
dbms_output.put_line(' LCM(48,99)-> ' || lcm(48,99) );
END;
/

Related

Programming PascalABC. Why is "output" without any text?

Even just in the middle of the program I inserted "write (OutPut, '2');" and even at the very end it is, but the "output" file is still created empty.
program HelloFromRussia;
var
s, y, h, n, x: Integer;
InPut, OutPut: Text;
begin
assign(InPut,'c:\input.txt');
assign(OutPut,'c:\output.txt');
reset(InPut);
rewrite(OutPut);
read(InPut, y);
write(OutPut, '1');
for var i:=1 to y do
begin
read(InPut, s);
if s mod 2 = 0 then write(OutPut, s, ' ');
end;
writeln(OutPut);
reset(InPut);
read(InPut, y);
for var i:=1 to y do
begin
read(InPut, s);
if s mod 2 <> 0 then writeln(OutPut);
write(OutPut, s, ' ');
end;
for h:=1 to y do begin
if s mod 2=0 then
n:=n+1;
if s mod 2<>0 then
x:=x+1;
end;
if (n>x) then writeln(OutPut, 'YES')
else writeln(OutPut, 'NO');
write(OutPut, '2');
close(InPut);
close(OutPut);
end.

Reading two dimensional pl/sql array

I am able to insert values but failed to retrieve values. Thanks in anticipation.
declare
type type1 is table of number;
type data_type is table of type1;
y data_type;
begin
y := data_type();
y.extend(100);
for i in 1..100 loop
y(i) := type1();
y(i).extend(100);
for j in 1..100 loop
y(i)(j) := i+j;
end loop;
end loop;
end;
If I understand well, you need a way to scan your arrays;
this could be a way:
declare
type type1 is table of number;
type data_type is table of type1;
y data_type;
k number := 2;
begin
y := data_type();
y.extend(k);
for i in 1..k loop
y(i) := type1();
y(i).extend(k);
for j in 1..k loop
y(i)(j) := i+j;
end loop;
end loop;
-- scanning
for i in y.first .. y.last loop
for j in y(i).first .. y(i).last loop
dbms_output.put_line('Y(' || i || ')(' || j || ') = ' || y(i)(j));
end loop;
end loop;
end;
the result:
Y(1)(1) = 2
Y(1)(2) = 3
Y(2)(1) = 3
Y(2)(2) = 4

Strange error in PLSQL script

I have a strange error on this pl/sql script
'PL/SQL: numeric or value error: character to number conversion error'
in the is_prime function
if((nr mod it) = 0)
HERE->then
return cast(0 as int);
end if;
I can't figure out what I did wrong, because I pass only int's to is_prime and I have declared only a int in is_prime...
set serveroutput on;
drop table exresult;
create table exresult(AA int,BB int);
create or replace function is_prime(nr in int) return int is
it int := 0;
begin
for it in 2..floor(sqrt(nr)) loop
if((nr mod it) = 0)
then
return cast(0 as int);
end if;
end loop;
return cast(1 as int);
end is_prime;
/
create or replace function sum_digits(nr in int) return int is
summ int := 0;
tmp int := nr;
begin
loop
summ := summ + (tmp mod 10);
tmp := floor(tmp / 10);
exit when tmp = 0;
end loop;
return summ;
end sum_digits;
/
declare
target constant int := 5;
nmod int := 0;
nprm int := 0;
it int := 0;
begin
for it in 1..10000 loop
nmod := sum_digits(it) mod 10;
nprm := is_prime(it);
dbms_output.put_line(it + ',' + nmod + ',' + nprm);
if(nmod = target)
then
insert into exresult select it, nprm from dual;
end if;
end loop;
end;
Your problem is actually here:
dbms_output.put_line(it + ',' + nmod + ',' + nprm);
+ is not the concatenation operator in PL/SQL, you need ||:
dbms_output.put_line(it || ',' || nmod || ',' || nprm);
That's relying on implicit conversion of the int values to varchar2, which is fine, but more correctly should be:
dbms_output.put_line(to_char(it) || ',' || to_char(nmod) || ',' || to_char(nprm));

ORACLE PL/SQL PIVOT procedure

I am trying to write an Oracle PL/SQL procedure to calculate a simple confusion matrix table. I have my labelled data prepared, basically two columns of 0 and 1, actual value vs predicted value.
I was able to calculate it with simple pivot (I think most straightforward option):
SELECT * FROM
( SELECT ACTUAL_VALUE, PREDICTED_VALUE
FROM MY_TABLE
)
PIVOT (
COUNT(PREDICTED_VALUE)
FOR PREDICTED_VALUE IN (1, 0))
ORDER BY ACTUAL_VALUE;
Now I am trying to "plug" all this into a DECLARE, BEGIN... framework but no success. Is it even possible to create procedure to calculate this pivot?
Thanks in advance for any suggestion!
I had to go with cursors and loops. And got my calculations working this way. So closing this one.Plus 3 more summing up calculations at the end.
Thank you
CREATE OR REPLACE PROCEDURE "mydb"."C_MATRIX"
IS
CURSOR MY_DATA IS
SELECT ACTUAL_CARD, PREDICTED_VALUE FROM my_table;
my_data_rec my_data%rowtype;
fp pls_integer := 0;
tp pls_integer := 0;
fn pls_integer := 0;
tn pls_integer := 0;
BEGIN
OPEN my_data;
LOOP
FETCH my_data INTO my_data_rec;
EXIT WHEN my_data%notfound;
IF my_data_rec.ACTUAL_CARD = 0 and my_data_rec.PREDICTED_VALUE = 0 then
tn := tn + 1;
elsif my_data_rec.ACTUAL_CARD = 0 and my_data_rec.PREDICTED_VALUE = 1 then
fn := fn + 1;
elsif my_data_rec.ACTUAL_CARD = 1 and my_data_rec.PREDICTED_VALUE = 1 then
tp := tp + 1;
elsif my_data_rec.ACTUAL_CARD = 1 and my_data_rec.PREDICTED_VALUE = 0 then
fp := fp + 1;
end if;
END LOOP;
dbms_output.put_line
('Number of false Positives: ' ||fp || ' Number of true Positives: ' ||tp || ' Total numbers of records: ' ||(fp + tp) );
dbms_output.put_line
('Number of false Negatives: ' ||fn || ' Number of true Negatives: ' ||tn || ' Total numbers of records: ' ||(fn + tn ));
dbms_output.put_line(' ');
dbms_output.put_line
(' Incorrect predictions: ' || (fp + fn) || ' Correct predictions: ' || (tp + tn) );
dbms_output.put_line(' ');
dbms_output.put_line(' Acurracy: ' || round((((tn + tp) / (tn + tp + fn + fp)) * 100),2) || '%');
dbms_output.put_line(' Precision: ' || round(((tp / (tp + fp)) * 100),2) || '%');
dbms_output.put_line(' Recall: ' || round(((tp / (tp + fn)) * 100),2) || '%');
END;
/

How write a PL/SQL program that prints out string which looking like xml format

Input String : “a4b4c2d9d9c2e6e6b4s2o1o1s2a4w2r8r8k3g5g5k3w2”
I tried this code as first step:
declare
word varchar2(50) := 'a4b4c2d9d9c2e6e6b4s2o1o1s2a4w2r8r8k2g5g5k2w2';
num number := length(word)/2;
name_array dbms_sql.varchar2_table;
begin
dbms_output.put_line(word);
FOR i IN 1..num LOOP
name_array(i) := substr(word, -2*i, 2);
END LOOP;
FOR i IN name_array.FIRST .. name_array.LAST LOOP
dbms_output.put_line(name_array(i));
END LOOP;
end;
This code creates only an array of string. Not xml format. I need this output:
Which SQL functions,conditional clauses... do I need to use?
Oracle Setup:
CREATE OR REPLACE TYPE CHARS_TABLE IS TABLE OF CHAR(2);
/
CREATE OR REPLACE TYPE INTEGERS_TABLE IS TABLE OF INTEGER;
/
PL/SQL:
This assumes a well-formed set of character pairs and just indents each pair to the appropriate level:
DECLARE
word VARCHAR2(50) := 'a4b4c2d9d9c2e6e6b4s2o1o1s2a4w2r8r8k2g5g5k2w2';
num PLS_INTEGER := LENGTH( word ) / 2;
name_array CHARS_TABLE := CHARS_TABLE();
depth_array INTEGERS_TABLE := INTEGERS_TABLE();
open_array INTEGERS_TABLE := INTEGERS_TABLE();
BEGIN
name_array.EXTEND( num );
depth_array.EXTEND( num );
open_array.EXTEND( num );
name_array(1) := SUBSTR( word, 1, 2 );
depth_array(1) := 1;
open_array(1) := 1;
FOR i IN 2 .. num LOOP
name_array(i) := SUBSTR( word, 2*i - 1, 2 );
open_array(i) := 1;
FOR j IN 1 .. i-1 LOOP
IF name_array(j) = name_array(i) THEN
open_array(i) := -open_array(i);
END IF;
END LOOP;
depth_array(i) := depth_array(i-1) + open_array(i);
END LOOP;
FOR i IN 1 .. num LOOP
FOR j IN 2 .. depth_array(i) + CASE open_array(i) WHEN 1 THEN 0 ELSE 1 END LOOP
DBMS_OUTPUT.PUT( ' ' );
END LOOP;
DBMS_OUTPUT.PUT_LINE( name_array(i) );
END LOOP;
END;
/
Output:
a4
b4
c2
d9
d9
c2
e6
e6
b4
s2
o1
o1
s2
a4
w2
r8
r8
k2
g5
g5
k2
w2
Update - Simpler Stack-Based Version:
DECLARE
word CONSTANT VARCHAR2(50) := 'a4b4c2d9d9c2e6e6b4s2o1o1s2a4w2r8r8k2g5g5k2w2';
num CONSTANT PLS_INTEGER := LENGTH( word ) / 2;
name_array CHARS_TABLE := CHARS_TABLE();
depth PLS_INTEGER := 0;
name CHAR(2);
PROCEDURE indent( depth PLS_INTEGER, name CHAR )
IS
BEGIN
FOR j IN 2 .. depth LOOP
DBMS_OUTPUT.PUT( ' ' );
END LOOP;
DBMS_OUTPUT.PUT_LINE( name );
END;
BEGIN
name_array.EXTEND( num );
FOR i IN 1 .. num LOOP
name := SUBSTR( word, 2*i - 1, 2 );
IF depth > 0 AND name = name_array(depth) THEN
indent(depth,name);
depth := depth - 1;
ELSE
depth := depth - 1;
name_array(depth) := name;
indent(depth,name);
END IF;
END LOOP;
END;
/
DECLARE
vs_CurrentChar VARCHAR2(1);
vs_NextChar VARCHAR2(1);
vs_TempText VARCHAR2(100);
vs_InputText VARCHAR2(100) := 'abcdffdcba';
vn_LengthOfText NUMBER := 1;
vn_WhileIndex NUMBER := 1;
vs_Spaces VARCHAR(100);
BEGIN
vs_TempText := NULL;
vs_CurrentChar := substr(vs_InputText, vn_WhileIndex, vn_LengthOfText);
dbms_output.put_line(vs_CurrentChar);
WHILE vn_WhileIndex < length(vs_InputText) - 1 LOOP
vs_NextChar := substr(vs_InputText, vn_WhileIndex + 1, vn_LengthOfText);
EXIT WHEN vs_CurrentChar = vs_NextChar;
vs_TempText := vs_TempText || vs_CurrentChar;
vs_CurrentChar := vs_NextChar;
vs_Spaces := NULL;
FOR i IN 1 .. vn_WhileIndex LOOP
vs_Spaces := vs_Spaces || chr(9); --'*';
END LOOP;
dbms_output.put_line(vs_Spaces || vs_CurrentChar);
vn_WhileIndex := vn_WhileIndex + 1;
END LOOP;
dbms_output.put_line(vs_Spaces || vs_CurrentChar);
FOR i IN 1 .. length(vs_TempText) LOOP
vs_Spaces := substr(vs_Spaces, vn_LengthOfText, length(vs_Spaces) - 1);
vs_CurrentChar := substr(vs_TempText, -i, vn_LengthOfText);
dbms_output.put_line(vs_Spaces || vs_CurrentChar);
END LOOP;
END;
/
And output:
a
b
c
d
f
f
d
c
b
a
even, if you put '*'; instead of chr(9); then output will look like as:
a
*b
**c
***d
****f
****f
***d
**c
*b
a

Resources