PL/SQL compilations error - oracle

CREATE OR REPLACE PROCEDURE Orden (n1 IN number, n2 IN number, n3 IN number) AS
menor number;
mediano number;
mayor number;
BEGIN
IF (n1<n2) THEN
IF (n1<n3) THEN
menor := n1;
IF (n2<n3) THEN
mediano := n2;
mayor := n3;
ELSE
mediano := n3;
mayor := n2;
END IF;
ELSE
menor := n3;
mediano :=n1;
mayor := n2;
END IF;
ELSE
IF (n1 < n3) THEN
menor := n2;
mediano := n1;
mayor := n3;
ELSE
mayor := n1;
IF(n2< n3) THEN
medio := n2;
menor := n3;
ELSE
medio := n3;
menor := n2;
END IF;
END IF;
n1 := menor;
n2 := medio;
n3 := mayor;
END;
/
The error is the next:
39/5 PLS-00103: Encountered the symbol ";" when expecting one of
the
following:
if

Three issues:
you are missing an END IF
medio is never declared; maybe you mean mediano?
if you want to assing a value to your input parameters, they need to be IN OUT.
An hint: CASE could be a more readable way to implement the same logic.

Related

Error: BREAK not allowed in for looping pascal

I try to create a for looping for my Bubble Sort Algorithm and use break as a condition if there is no more number to be sorted anymore. But then the compiler said that BREAK not allowed. Here is my code
Procedure Sort(var data : arr; j : integer);
var
temp: integer;
begin
temp := data[j];
data[j] := data[j + 1];
data[j + 1] := temp;
end;
Procedure sortDescending(var data : arr; n : integer);
var
i, j : integer;
marker : boolean;
begin
for i := 1 to n do
marker := false;
begin
for j := 1 to n do
begin
if(data[j] < data[j + 1]) then
begin
Sort(data, j);
marker := true;
end;
end;
if(marker = false) then
begin
break;
end;
end;
end;
Here's your code.
for i := 1 to n do
marker := false;
begin
for j := 1 to n do
begin
if(data[j] < data[j + 1]) then
begin
Sort(data, j);
marker := true;
end;
end;
if(marker = false) then
begin
break;
end;
end;
Let's add some whitespace after loops and indentation to make the issue clearer.
for i := 1 to n do
marker := false;
begin
for j := 1 to n do
begin
if (data[j] < data[j + 1]) then
begin
Sort(data, j);
marker := true;
end;
end;
if (marker = false) then
begin
break;
end;
end;
Which is equivalent to:
for i := 1 to n do
marker := false;
for j := 1 to n do
begin
if (data[j] < data[j + 1]) then
begin
Sort(data, j);
marker := true;
end;
end;
if (marker = false) then
begin
break;
end;
The break is not within a loop.
You likely meant to put begin before marker := false;.
for i := 1 to n do
begin
marker := false;
for j := 1 to n do
begin
if (data[j] < data[j + 1]) then
begin
Sort(data, j);
marker := true;
end;
end;
if (marker = false) then
begin
break;
end;
end;

Unit1.pas(72): 'END' expected but 'ELSE' found

begin
D:=StrToFloat(Edit1.Text);
if (Edit1.Text <= '3' ) And (Edit2.Text >= '1') and (Edit3.Text = '1' ) then
begin
Edit4.Text := '6,3' ;
Edit5.Text := '11-12';
Edit6.Text := '60';
Edit7.Text := '100';
end
else
begin
if(Edit1.Text <= '3' ) And (Edit2.Text >= '1') and (Edit3.Text = '2' ) then
Edit4.Text := '3,2' ;
Edit5.Text := '9-10';
Edit6.Text := '25';
Edit7.Text := '40'
end
else
begin
if(Edit1.Text <= '3' ) And (Edit2.Text >= '1') and (Edit3.Text = '3' ) then
Edit4.Text := '1,6' ;
Edit5.Text := '8-9';
Edit6.Text := '25';
Edit7.Text := '40';
end
end;
I have some trouble identifing the problem of if else Delphi 7 statement
[Error] Unit1.pas(73): ';' expected but 'BEGIN' found error.
Your code has mismatched begin..end pairs. Fix the indentation and you will see this more clearly:
begin
D:=StrToFloat(Edit1.Text);
if (Edit1.Text <= '3' ) And (Edit2.Text >= '1') and (Edit3.Text = '1' ) then
begin
Edit4.Text := '6,3' ;
Edit5.Text := '11-12';
Edit6.Text := '60';
Edit7.Text := '100';
end
else
begin
if (Edit1.Text <= '3' ) And (Edit2.Text >= '1') and (Edit3.Text = '2' ) then
Edit4.Text := '3,2';
Edit5.Text := '9-10';
Edit6.Text := '25';
Edit7.Text := '40'
end
else
begin
if(Edit1.Text <= '3' ) And (Edit2.Text >= '1') and (Edit3.Text = '3' ) then
Edit4.Text := '1,6' ;
Edit5.Text := '8-9';
Edit6.Text := '25';
Edit7.Text := '40';
end
You have an erroneous if..else..else sequence.
I'm guessing you meant to do something more like this instead:
begin
D := StrToFloat(Edit1.Text);
if (Edit1.Text <= '3') And (Edit2.Text >= '1') and (Edit3.Text = '1') then
begin
Edit4.Text := '6,3' ;
Edit5.Text := '11-12';
Edit6.Text := '60';
Edit7.Text := '100';
end
else if (Edit1.Text <= '3') And (Edit2.Text >= '1') and (Edit3.Text = '2') then
begin
Edit4.Text := '3,2';
Edit5.Text := '9-10';
Edit6.Text := '25';
Edit7.Text := '40'
end
else if (Edit1.Text <= '3' ) And (Edit2.Text >= '1') and (Edit3.Text = '3') then
begin
Edit4.Text := '1,6' ;
Edit5.Text := '8-9';
Edit6.Text := '25';
Edit7.Text := '40';
end
...
Which can be simplified a little to remove the redundant comparisons:
begin
D := StrToFloat(Edit1.Text);
if (Edit1.Text <= '3') And (Edit2.Text >= '1') then
begin
if (Edit3.Text = '1') then
begin
Edit4.Text := '6,3' ;
Edit5.Text := '11-12';
Edit6.Text := '60';
Edit7.Text := '100';
end
else if (Edit3.Text = '2') then
begin
Edit4.Text := '3,2';
Edit5.Text := '9-10';
Edit6.Text := '25';
Edit7.Text := '40'
end
else if (Edit3.Text = '3') then
begin
Edit4.Text := '1,6' ;
Edit5.Text := '8-9';
Edit6.Text := '25';
Edit7.Text := '40';
end
...
end
...
Also, note that you can't use operators like <= and >= to compare strings as if they were numbers. You have to convert the string values to numeric values first. Which you seem to already be aware of by your use of StrToFloat(), but you are ignoring that value afterwards. Try something like this:
begin
D1 := StrToFloat(Edit1.Text);
D2 := StrToFloat(Edit2.Text);
D3 := StrToFloat(Edit3.Text);
if (D1 <= 3) And (D2 >= 1) then
begin
if (D3 = 1) then
begin
Edit4.Text := '6,3' ;
Edit5.Text := '11-12';
Edit6.Text := '60';
Edit7.Text := '100';
end
else if (D3 = 2) then
begin
Edit4.Text := '3,2';
Edit5.Text := '9-10';
Edit6.Text := '25';
Edit7.Text := '40'
end
else if (D3 = 3) then
begin
Edit4.Text := '1,6' ;
Edit5.Text := '8-9';
Edit6.Text := '25';
Edit7.Text := '40';
end
...
end
...

how to populate an Associative Array index by VARCHAR2

I have 2 associative arrays:
v1 index by binary integer
v2 index by varchar2
type r1 is record
( c1 number
, c2 varchar2(64));
type t1 is table of r1 index by binary_integer;
v1 t1;
type t2 is table of varchar2(64) index by binary_integer;
v2 t2;
counter number := 0;
type r3 is record
( no_visits number);
type t3 is table of r3 index by varchar2(64);
v3 t3;
I want to have a list (probably another associative array - v3 with the cities from v1 which are defined in v2 and how many times I have visited them (the visits are defined in v1).
I was thinking that v3 to be index by VARCHAR2 (the index to be the name of the cities) and contains only one value, the number of visits.
Is it possible to have implement something like:
begin
v1(1).c1 := 1990;
v1(1).c2 := 'PARIS';
V1(2).c1 := 2000;
V1(2).c2 := 'PARIS';
v1(3).c1 := 2001;
v1(3).c2 := 'PARIS';
v1(4).c1 := 1992;
v1(4).c2 := 'MADRID';
v1(5).c1 := 1994;
v1(5).c2 := 'LONDON';
v1(6).c1 := 1998;
v1(6).c2 := 'PRAGUE';
v2(1) := 'PARIS';
v2(2) := 'LONDON';
v2(3) := 'MADRID';
for i in 1 .. v1.count loop
for j in 1 .. v2.count loop
if v1(i).c2 = v2(j)
then
v3(v2(j).c2) := counter + 1;
end if;
end loop;
end loop;
end;
Initialize v3 with values from v2, modify counting loop slightly and show results in final loop:
declare
type r1 is record ( c1 number, c2 varchar2(64));
type t1 is table of r1 index by binary_integer;
v1 t1;
type t2 is table of varchar2(64) index by binary_integer;
v2 t2;
type r3 is record( no_visits number);
type t3 is table of r3 index by varchar2(64);
v3 t3;
begin
v1(1).c1 := 1990;
v1(1).c2 := 'PARIS';
V1(2).c1 := 2000;
V1(2).c2 := 'PARIS';
v1(3).c1 := 2001;
v1(3).c2 := 'PARIS';
v1(4).c1 := 1992;
v1(4).c2 := 'MADRID';
v1(5).c1 := 1994;
v1(5).c2 := 'LONDON';
v1(6).c1 := 1998;
v1(6).c2 := 'PRAGUE';
v2(1) := 'PARIS';
v2(2) := 'LONDON';
v2(3) := 'MADRID';
for i in 1..v2.count loop
v3(v2(i)).no_visits := 0;
end loop;
for i in 1 .. v1.count loop
for j in 1 .. v2.count loop
if v1(i).c2 = v2(j) then
v3(v2(j)).no_visits := v3(v2(j)).no_visits + 1;
end if;
end loop;
end loop;
for i in 1..v2.count loop
dbms_output.put_line('City: '||v2(i));
dbms_output.put_line('Visited: '||v3(v2(i)).no_visits);
end loop;
end;
Output:
City: PARIS
Visited: 3
City: LONDON
Visited: 1
City: MADRID
Visited: 1
In general, yes, you can do that. In this case there are some problems - for example, in the line v3(v2(j).c2) := counter + 1; there's no c2 element in v2 so you'll get a compilation error there, and in that same line the v3 reference should be followed by .no_visits, but generally speaking what you're trying to do here is certainly allowed by the language.

How can I print an associative array as a matrix

I'm creating 2 associative arrays in which I put random values from 0 to 30, and after that I want to print then as a matrix. Is there a way I can do that?
Here is my code:
set serveroutput on
DECLARE
TYPE MyTab IS TABLE OF NUMBER INDEX BY VARCHAR2(10);
mat1 MyTab;
mat2 MyTab;
v_n NUMBER(2);
v_m NUMBER(2);
v_nr NUMBER(3);
v_dim NUMBER(3);
BEGIN
v_n := round(dbms_random.value(2,5));
v_m := round(dbms_random.value(2,5));
v_nr := 1;
v_dim := v_n*v_m;
DBMS_OUTPUT.PUT_LINE(v_n||' '||v_m);
FOR i in 1 ..v_dim LOOP
mat1(v_nr) := round(dbms_random.value(0,30));
v_nr := v_nr+1;
END LOOP;
v_nr := 1;
FOR i in 1 ..v_dim LOOP
mat2(v_nr) := round(dbms_random.value(0,30));
v_nr := v_nr+1;
END LOOP;
FOR i in 1 ..v_dim LOOP
DBMS_OUTPUT.PUT_LINE(mat1(i));
END LOOP;
DBMS_OUTPUT.PUT_LINE(chr(10));
FOR i in 1 ..v_dim LOOP
DBMS_OUTPUT.PUT_LINE(mat2(i));
END LOOP;
END;
/
I just understood there are 2 matrixes, mat1 and mat2, which have various size (but both have same dimensions).
Here is how to display them:
set serveroutput on
DECLARE
TYPE MyTab IS TABLE OF NUMBER INDEX BY pls_integer;
mat1 MyTab;
mat2 MyTab;
v_n pls_integer;
v_m pls_integer;
v_nr pls_integer;
v_dim pls_integer;
BEGIN
v_n := round(dbms_random.value(2,5));
v_m := round(dbms_random.value(2,5));
if (v_n > v_m) then
-- switch values for V_m to be the biggest dim
v_nr:=v_n;
v_n:=v_m;
v_m:=v_nr;
end if;
v_nr := 1;
v_dim := v_n*v_m;
DBMS_OUTPUT.PUT_LINE(v_n||' '||v_m);
FOR i in 1 ..v_dim LOOP
mat1(v_nr) := round(dbms_random.value(0,30));
v_nr := v_nr+1;
END LOOP;
v_nr := 1;
FOR i in 1 ..v_dim LOOP
mat2(v_nr) := round(dbms_random.value(0,30));
v_nr := v_nr+1;
END LOOP;
DBMS_OUTPUT.PUT_LINE('MATRIX1');
FOR i in 1 ..v_n LOOP
FOR j in 1 ..v_m LOOP
DBMS_OUTPUT.PUT(' - '|| rpad(mat1((j-1)*v_n + i), 4));
END LOOP;
DBMS_OUTPUT.PUT_LINE('');
END LOOP;
DBMS_OUTPUT.PUT_LINE('MATRIX2');
FOR i in 1 ..v_n LOOP
FOR j in 1 ..v_m LOOP
DBMS_OUTPUT.PUT(' - '|| rpad(mat2((j-1)*v_n + i), 4));
END LOOP;
DBMS_OUTPUT.PUT_LINE('');
END LOOP;
END;
/
I changed the types to pls_integer which looks more simple. Then keep in mind that I put the matrices in the good form where they can be multiplied (swith v_nand v_m in the loops, and added formatting to understand what happens.
DECLARE
TYPE MyTab IS TABLE OF NUMBER INDEX BY pls_integer;
mat1 MyTab;
mat2 MyTab;
v_n pls_integer;
v_m pls_integer;
v_nr pls_integer;
v_dim pls_integer;
idx pls_integer;
idx1 pls_integer;
idx2 pls_integer;
v_p number;
BEGIN
v_n := round(dbms_random.value(2,5));
v_m := round(dbms_random.value(2,5));
-- v_n := 2; -- formating works better with 2 and 3
-- v_m := 3;
v_nr := 1;
v_dim := v_n*v_m;
DBMS_OUTPUT.PUT_LINE(v_n||' '||v_m);
FOR i in 1 ..v_dim LOOP
mat1(v_nr) := round(dbms_random.value(0,30));
v_nr := v_nr+1;
END LOOP;
v_nr := 1;
FOR i in 1 ..v_dim LOOP
mat2(v_nr) := round(dbms_random.value(0,30));
v_nr := v_nr+1;
END LOOP;
DBMS_OUTPUT.PUT_LINE('MATRIX1:a');
FOR i in 1 ..v_n LOOP
DBMS_OUTPUT.PUT(' .................. ');
FOR j in 1 ..v_m LOOP
idx:=(j-1)*v_n + i;
DBMS_OUTPUT.PUT(' |'||j||','||i||'a['||idx||']'|| rpad(mat1(idx), 4));
END LOOP;
DBMS_OUTPUT.PUT_LINE('');
END LOOP;
DBMS_OUTPUT.PUT_LINE('MATRIX2:b');
FOR i in 1 ..v_m LOOP
FOR j in 1 ..v_n LOOP
idx:=(j-1)*v_m + i;
DBMS_OUTPUT.PUT(' |'||j||','||i||'b['||idx||']'|| rpad(mat2(idx), 4));
END LOOP;
DBMS_OUTPUT.PUT_LINE('');
END LOOP;
DBMS_OUTPUT.PUT_LINE('product: a x b');
FOR L in 1 ..v_m LOOP
DBMS_OUTPUT.PUT(' ---------------------------');
FOR K in 1 ..v_m LOOP
v_p:=0;
DBMS_OUTPUT.PUT(' | ');
FOR j in 1 ..v_n LOOP
idx1 := j + (K-1)*v_n;
idx2 := (j-1)*v_m + L;
v_p := v_p + mat1(idx1) * mat2(idx2) ;
DBMS_OUTPUT.PUT('a['||idx1||']b['||idx2||']+');
END LOOP;
DBMS_OUTPUT.PUT('->'|| rpad(v_p, 4));
END LOOP;
DBMS_OUTPUT.PUT_LINE('');
END LOOP;
END;
/
Do you want to use Matrix for calculation or logging?
It is quite difficult to logging with Matrix. I don't think it is a good way. If you insist, here's the code.
FOR i in 1 ..v_n LOOP
FOR j in 1 ..v_m LOOP
DBMS_OUTPUT.PUT( mat.at<double>(i,j));

How to write numbers separated with commas in a loop on one line?

I am making a program of prime number in FreePascal.
How to output number divides with I1,I2 separated with commas instead of 2 lines?
var
P:Integer;
I:Integer;
J:Integer;
A:Integer;
begin
writeln('Prime number program');
writeln;
writeln('Insert number');
readln(P);
for I:=2 to P-1 do
begin
J:=P Mod I;
if (J=0) then
begin
writeln(P,' divides with ',I);
a:=a+1
end;
end;
if a=0 then
begin
writeln(P,' is prime number')
end;
end.
I know it's not a good way to teach you something, but here it is:
program Project1;
uses
SysUtils;
var
S: string;
I: Integer;
Count: Integer;
Input: Integer;
begin
Writeln('Prime number program');
Writeln;
Writeln('Insert a number:');
Readln(Input);
for I := 2 to Input-1 do
begin
if (Input mod I = 0) then
begin
Count := Count + 1;
if (S <> '') then
S := S + ', ';
S := S + IntToStr(I);
end;
end;
if (Count = 0) then
Writeln(Input, ' is a prime number.')
else
Writeln(Input, ' is not a prime number. It divides with ', S, '.');
Readln;
end.
prime := true;
for i := 2 to p - 1 do
if(p mod i = 0) then prime := false;
if prime then writeln("prime");
all program:
program Prime;
var
prime: boolean;
I, P: Integer;
begin
Writeln('Prime number program');
Writeln;
Writeln('Insert a number:');
Readln(P);
prime := true;
for i := 2 to p - 1 do
if(p mod i = 0) then prime := false;
if prime then writeln("prime");
else writeln("not prime");
Readln;
end.
No need to check all numbers below N, odd numbers below sqrt(N) are enough.
program PrimeTest;
var N, I, Divisor: LongInt;
Prime: Boolean;
begin
writeln('Prime number program');
writeln;
write('Insert number: ');
readln(N);
Divisor := 1;
Prime := True;
if N < 5 then
begin
Prime := (N = 2) or (N = 3);
if N = 4 then Divisor := 2;
end else if Odd(N) then
begin
I := 3;
while I*I <= N do
begin
if N mod I = 0 then
begin
Prime := False;
Divisor := I;
break;
end;
I := I + 2;
end;
end else begin
Prime := False;
Divisor := 2;
end;
if Prime then writeln(N, ' is a prime number')
else writeln(N, ' is divisible by ', Divisor);
end.
Of course, if you want to find all prime factors, or all divisors (not the same thing), you will need something a bit more complcated, but it's still better to do as few divisions as possible.
Here is a solution giving the whole prime factorization.
program PrimeTest;
var N, I, J, Index, M: LongInt;
Factor, Power: array[1 .. 32] of LongInt;
begin
writeln('Prime number program');
writeln;
write('Insert number: ');
readln(N);
M := N;
Index := 0;
if N mod 2 = 0 then
begin
J := 0;
while N mod 2 = 0 do
begin
Inc(J);
N := N div 2;
end;
Inc(Index);
Factor[Index] := 2;
Power[Index] := J;
end;
I := 3;
while I*I <= N do
begin
if N mod I = 0 then
begin
J := 0;
while N mod I = 0 do
begin
Inc(J);
N := N div I;
end;
Inc(Index);
Factor[Index] := I;
Power[Index] := J;
end;
I := I + 2;
end;
if (N > 1) or (Index = 0) then
begin
Inc(Index);
Factor[Index] := N;
Power[Index] := 1;
end;
if M = 1 then writeln('1 is not prime')
else if (Index > 1) or ((Index > 0) and (Power[1] > 1)) then
begin
if Power[1] = 1 then write(M, ' = ', Factor[1])
else write(M, ' = ', Factor[1], '^', Power[1]);
for I := 2 to Index do
begin
if Power[I] = 1 then write(' * ', Factor[I])
else write(' * ', Factor[I], '^', Power[I]);
end;
writeln;
end else writeln(M, ' is prime');
end.

Resources