bind variable not declared error when using procedure in pl/sql - oracle

`
declare
x number:=&x;
y number:=&y;
m number;
s1 number;
a1 number;
create or replace procedure z(x in number,y in number,m out number,s1 out number,a1 out number)
is
begin
if x<y
then
m:=x;
else
m:=y;
end if;
s1:=a+b;
a1:s1/2;
end z;
/
begin
z(x,y,m,s1,a1);
dbms_output.put_line('Sum:'||sum1);
end;
/
/
I am trying to find the min sum and average of 2 numbers inputted by the user using pl/sql procedure

You can't use things you didn't declare. Also, it is good to check for syntax errors.
See comments:
SQL> create or replace procedure z(x in number,y in number,m out number,s1 out number,a1 out number)
2 is
3 begin
4 if x<y
5 then
6 m:=x;
7 else
8 m:=y;
9 end if;
10 s1:=x+y; --> x and y not a and b
11 a1:=s1/2; --> := not just :
12 end z;
13 /
Procedure created.
Testing:
SQL> declare
2 x number:=&x;
3 y number:=&y;
4 m number;
5 s1 number;
6 a1 number;
7 begin
8 z(x,y,m,s1,a1);
9 dbms_output.put_line('Sum:'||s1); --> s1 not sum1
10 end;
11 /
Enter value for x: 3
Enter value for y: 5
Sum:8
PL/SQL procedure successfully completed.
SQL>

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>

what is wrong with the way I write procedures and functions in plsql?

1 declare
2 a number;
3 b number;
4 c number;
5 d number;
6 PROCEDURE findMin(x IN number, y IN number, z IN number , L out number) IS
7 BEGIN
8 IF x > y&& x>z then
9 L:= x;
10 ELSE if y>z&&y>x then
11 L:= y;
12 else
13 L:=z
14 END IF;
15 End if;
16 END;
17 BEGIN
18 a:= 23;
19 b:= 45;
20 c:=36;
21 findMin(a, b, c,d);
22 dbms_output.put_line(' Minimum of (23, 45,36) : ' || d);
END;
this is the first one I couldnt unerstand what is wrong with this code it is showing
*
ERROR at line 1:
ORA-06540: PL/SQL: compilation error
ORA-06553: PLS-906: Compilation is not possible
the second one is
2. DECLARE
3. num number;
4. c number;
5. PROCEDURE fact(x IN number, f out number) IS
6. BEGIN
7. IF x = 0 THEN
8. f:= x;
9. ELSE
10. f:= x*fact(x-1);
11. END IF;
12. END;
13. BEGIN
14. c:=f;
15. num:=6
16. fact(num,c);
17. dbms_output.put_line(' Factorial: ' ||'is'||c);
18. END;
19. /
i am getting output as
z:= x*fact(x-1) ;
*
ERROR at line 9:
ORA-06550: line 9, column 14:
PLS-00306: wrong number or types of arguments in call to 'FACT'
ORA-06550: line 9, column 8:
PL/SQL: Statement ignored
this is the second procedure i wrote but i couldnt get the problem in it
1 create or replace function tables(n in number) return number is s number;
2 begin
3 i number;
4 for i in 1...10 loop
5 s:=n*i;
6 end loop;
7 return s ;
8* end;
this is the multiplication table function what is wrong with my codes they are showing output as
Warning: Function created with compilation errors.
As of your 1st code: you should use AND, not && and terminate statements with a colon. When fixed, it runs (and produces wrong result, though, but I'll leave it to you):
SQL> DECLARE
2 a NUMBER;
3 b NUMBER;
4 c NUMBER;
5 d NUMBER;
6
7 PROCEDURE findMin (x IN NUMBER,
8 y IN NUMBER,
9 z IN NUMBER,
10 L OUT NUMBER)
11 IS
12 BEGIN
13 IF x > y
14 AND x > z
15 THEN
16 L := x;
17 ELSE
18 IF y > z
19 AND y > x
20 THEN
21 L := y;
22 ELSE
23 L := z;
24 END IF;
25 END IF;
26 END;
27 BEGIN
28 a := 23;
29 b := 45;
30 c := 36;
31 findMin (a,
32 b,
33 c,
34 d);
35 DBMS_OUTPUT.put_line (' Minimum of (23, 45,36) : ' || d);
36 END;
37 /
Minimum of (23, 45,36) : 45
PL/SQL procedure successfully completed.
SQL>
All that (37 lines of code) could be shortened to only one (which actually works):
SQL> select least(23, 45, 36) minimum from dual;
MINIMUM
----------
23
SQL>
As of your 2nd code: procedure is wrong as fact can't be used that way and lacks in 2nd parameter. One option to fix it is
SQL> DECLARE
2 num NUMBER;
3 c NUMBER;
4
5 PROCEDURE fact (x IN NUMBER, f OUT NUMBER)
6 IS
7 l_var NUMBER := 1;
8 BEGIN
9 FOR i IN 1 .. x
10 LOOP
11 l_var := l_var * i;
12 END LOOP;
13
14 f := l_var;
15 END;
16 BEGIN
17 num := 6;
18 fact (num, c);
19 DBMS_OUTPUT.put_line (' Factorial of ' || num || ' is ' || c);
20 END;
21 /
Factorial of 6 is 720
PL/SQL procedure successfully completed.
SQL>
Finally, the 3rd code: I have no idea what you meant to say with it, it's full of errors. I tried to salvage it, can't tell whether I succeeded.
SQL> CREATE OR REPLACE FUNCTION tables (n IN NUMBER)
2 RETURN NUMBER
3 IS
4 s NUMBER := 0;
5 BEGIN
6 FOR i IN 1 .. 10
7 LOOP
8 s := s + n * i;
9 END LOOP;
10
11 RETURN s;
12 END;
13 /
Function created.
SQL> SELECT tables (3) FROM DUAL;
TABLES(3)
----------
165
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

How to create two variables refering the same nested table?

I expected that in the following code variables x and y refer the same nested table object but expression y = x seems to create empty table in y. So output is surprisingly 'No: a c' ( however I expected 'Yes: a b c'). What should I do in PL/SQL to have y referring the same nested table object as x.
declare
type str_t is table of varchar(100);
x str_t := str_t ();
y str_t ;
begin
x.extend; x(x.last) := 'a';
y := x;
y.extend; y(y.last) := 'b';
x.extend; x(x.last) := 'c';
dbms_output.put_line(case when x=y then 'Yes: ' else 'No: ' end);
for i in x.first .. x.last
loop
dbms_output.put_line(x(i));
end loop;
Сan it (passing nested table by reference - not by value) be written in PL/SQL or it's fundamentally impossible? Does any alternatives exist in the language to aviod the problem?
PL/SQL doesn't have references (but in one place we'll see later) so essentially what you're asking is impossible in PL/SQL. I don't see how that can be a problem, though.
In your example x and y are two different variables that are having the same type (a nested table collection), x := y is a variable assigment (deep copy), x = y is a comparison. See also e.g. Assigning Values to Variables.
I guess you've programming background with some other languages and you're trying to apply some other language paradigm here. You also might have an XY-problem.
One alternative is to use two different index variables to access the collection. That might or might not suit for your case:
declare
type str_list_t is table of varchar2(32767);
v_foos constant str_list_t := str_list_t('a', 'b', 'c');
-- have some business logic to get the right indices
i pls_integer := 1;
j pls_integer := 3;
begin
dbms_output.put_line(v_foos(i));
dbms_output.put_line(v_foos(j));
end;
/
But please note that changes to collection will invalidate the index variables (that's why I declared a constant collection).
When working with nested tables check also SQL multiset conditions that provide a powerful manipulations.
The only place with reference semantics is subprogram parameters where different parameter modes (IN, OUT or IN OUT) have different semantics (pass-by-value or pass-by-reference). But even there the decision is made by PL/SQL compiler/runtime - programmer has no much control.
So output is surprisingly 'No: a c' ( however I expected 'Yes: a b c').
Your expectation is wrong. Since the two arrays are having different values.
Let's see step by step:
x.extend;
x(x.last) := 'a';
So, x has value a.
y := x;
x is copied to y, so y has value a.
y.extend;
y(y.last) := 'b';
Now, y has a and b.
x.extend;
x(x.last) := 'c';
Now, x has a and c.
Finally,
X --> a,c
Y --> a,b
Let's see what your code shows the output:
SQL> set serveroutput on
SQL> DECLARE
2 type str_t
3 IS
4 TABLE OF VARCHAR(100);
5 x str_t := str_t ();
6 y str_t ;
7 BEGIN
8 x.extend;
9 x(x.last) := 'a';
10 y := x;
11 y.extend;
12 y(y.last) := 'b';
13 x.extend;
14 x(x.LAST) := 'c';
15 FOR i IN x.first .. x.last
16 LOOP
17 dbms_output.put_line('X'||'-'||x(i));
18 END LOOP;
19 FOR i IN y.first .. y.last
20 LOOP
21 dbms_output.put_line('Y'||'-'||y(i));
22 END LOOP;
23 END;
24 /
X-a
X-c
Y-a
Y-b
PL/SQL procedure successfully completed.
SQL>
So, X and Y are not equal.
To make them equal, set Y = X:
SQL> set serveroutput on
SQL> DECLARE
2 type str_t
3 IS
4 TABLE OF VARCHAR(100);
5 x str_t := str_t ();
6 y str_t ;
7 BEGIN
8 x.extend;
9 x(x.LAST) := 'a';
10 x.extend;
11 x(x.last) := 'b';
12 x.extend;
13 x(x.LAST) := 'c';
14 y := x;
15 dbms_output.put_line(case when x=y then 'Yes: ' else 'No: ' end);
16 FOR i IN x.first .. x.last
17 LOOP
18 dbms_output.put_line('X'||'-'||x(i));
19 END LOOP;
20 END;
21 /
Yes:
X-a
X-b
X-c
PL/SQL procedure successfully completed.
SQL>

Resources