how to populate an Associative Array index by VARCHAR2 - oracle

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.

Related

How can I show the sorting progress step by step on output screen?

I don't know how to make sorting process visible on output.. (like you can see the step by step of each sorting phase on output).
Below is example of a similar program.
And here's my current progress:
program insertsort;
const
max = 100;
type
arr = array [1..max] of integer;
var
data : arr;
n, i, j : integer;
procedure InsertionSort(size : integer);
var
i, j, index : integer;
begin
for i := 2 to size do
begin
index := data[i];
j := i;
while ((j > 1) and (data[j-1] < index)) do
begin
data[j] := data[j-1];
j := j - 1;
end;
data[j] := index;
end;
end;
begin
write('Input Data : ');
readln(n);
for i := 1 to n do
begin
write ('Data-',i,' = '); readln(data[i]);
end;
writeln;
write ('Unsorted : ');
for i := 1 to n do
write(data[i],' ');
InsertionSort(max);
writeln;
writeln;
writeln;
write('Sorted : ');
for i := 1 to n do
write(data[i],' ');
readln;
end.

Reverse the given number program in PL/SQL

I was trying to execute this program but it only outputs the ~ symbol.
This is the code:
DECLARE
N_NUM NUMBER := 234;
N_REM NUMBER;
N_REV NUMBER := 0;
BEGIN
WHILE N_NUM != 0
LOOP
N_REM := MOD (N_NUM, 10);
N_NUM := (N_NUM / 10);
N_REV := N_REV * 10 + N_REM;
END LOOP;
DBMS_OUTPUT.PUT_LINE (N_REV);
END;
Before dividing by 10 you have to subtract the remainder. The following code will work.
DECLARE
N_NUM NUMBER := 234;
N_REM NUMBER;
N_REV NUMBER := 0;
BEGIN
WHILE N_NUM <> 0
LOOP
N_REM := MOD (N_NUM, 10);
N_NUM := ( (N_NUM - N_REM) / 10);
N_REV := N_REV * 10 + N_REM;
END LOOP;
DBMS_OUTPUT.PUT_LINE (N_REV);
END;
Use Floor function as shown below:
N_NUM := FLOOR(N_NUM/10)
As this floor function returns only 23 instead of 23.4
A second option is using the REVERSE() function.
However, that function would like to input a CHAR, not a NUMBER.
So you will have to convert that first.
For example:
DECLARE
N_Num NUMBER := 234;
N_Rev NUMBER := 0;
BEGIN
SELECT REVERSE(TO_CHAR(N_Num)) INTO N_Rev FROM Dual;
DBMS_OUTPUT.PUT_LINE (N_Rev);
END;
/
create or replace function ReverseNo(no1 in number)
return number
Is
n number:=no1;
p number;
c number:=0;
begin
while ( n>0)
LOOP
p:=mod(n,10);
c:=c*10+p;
n:=(n-p)/10;
END LOOP;
DBMS_OUTPUT.PUT_LINE('NO IS ' || c);
return c;
end;

GET_TIME in Oracle

I have a code that is supposed to give me the compilation time for the procedure, but it only gets me 0 secs! Is the calculation wrong? Is there any other way?
create or replace PROCEDURE proc_time AS
v NUMBER := 1;
x NUMBER := 0;
counter number := 0;
summ NUMBER;
ex_start NUMBER;
ex_end NUMBER;
ex_time NUMBER;
BEGIN
ex_start := dbms_utility.get_time;
while counter <= 19
loop
counter := counter + 1;
summ := x+v;
x := v;
V := summ;
dbms_output.put_line('Fibonacci nr'||counter||': '||summ);
END loop;
ex_end := DBMS_UTILITY.GET_TIME;
ex_time := (ex_end-ex_start)/100;
DBMS_OUTPUT.PUT_LINE( 'Exekveringstid: ' || ex_time || ' sekunder.' );
END;
/
As explained in the above answer by Lalit. Your snippet runs too fast
to calculate the time difference. Try to increase the while loop with
some greater number and here you go !!!
CREATE OR REPLACE PROCEDURE proc_time
AS
v NUMBER := 1;
x NUMBER := 0;
counter NUMBER := 0;
summ NUMBER;
ex_start NUMBER;
ex_end NUMBER;
ex_time NUMBER;
BEGIN
ex_start := dbms_utility.get_time;
dbms_output.put_line('start time ==>'||NVL(ex_start,0));
WHILE counter <= 190000
LOOP
counter := counter + 1;
summ := x +v;
x := v;
V := summ;
-- dbms_output.put_line('Fibonacci nr'||counter||': '||summ);
END LOOP;
ex_end := DBMS_UTILITY.GET_TIME;
dbms_output.put_line('End time ==>'||ex_end);
ex_time := (ex_end-ex_start);
DBMS_OUTPUT.PUT_LINE( 'Exekveringstid: ' || ex_time || ' sekunder.' );
END;
set serveroutput on;
exec proc_time;
-------------------------------OUTPUT----------------------------------------
start time ==>1761607275
End time ==>1761607281
Exekveringstid: 6 sekunder.
As an alternative use the TIMESTAMP data type, this supports up to nanoseconds (provided your server supports it as well)
DECLARE
ex_start TIMESTAMP(9);
Duration INTERVAL DAY TO SECOND;
v NUMBER := 1;
x NUMBER := 0;
counter NUMBER := 0;
summ NUMBER;
BEGIN
ex_start := LOCALTIMESTAMP;
WHILE counter <= 10000 LOOP
counter := counter + 1;
summ := x +v;
x := v;
V := summ;
END LOOP;
Duration := LOCALTIMESTAMP - ex_start;
DBMS_OUTPUT.PUT_LINE ( EXTRACT(SECOND FROM Duration) /1000||' msec.');
END;
Perhaps, it is executing too quickly. You can try to increase the number of loops instead of 19 to something larger.
Also, it would give you the execution time, not the compilation time. The procedure is already compiled and stored in database. The time in the output is at run time, i.e. when you execute the procedure.
For example,
SQL> CREATE OR REPLACE PROCEDURE test_time
2 AS
3 l_start NUMBER;
4 l_loops NUMBER := 10000000;
5 l_number NUMBER := 0;
6 BEGIN
7 l_start := DBMS_UTILITY.get_time;
8 FOR i IN 1 .. l_loops
9 LOOP
10 l_number := l_number + i;
11 END LOOP;
12 DBMS_OUTPUT.put_line('time taken: ' || (DBMS_UTILITY.get_time - l_start) || ' hsecs');
13 END test_time;
14 /
Procedure created.
SQL> set serveroutput on
SQL> BEGIN
2 test_time;
3 END;
4 /
time taken: 101 hsecs
PL/SQL procedure successfully completed.
SQL>

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));

Permutation of numbers - all possible combinations [duplicate]

this is my simple code to generate
all possible combinations of a set for
example
1,2,3:
Display:
123
132
213
231
312
321
i want to create variable number of for loops to let the user determine the length of given string...
does anyone have an idea...
thank's in advance.
type
TNumber = '0'..'9';
procedure TForm1.Button1Click(Sender: TObject);
var
Numbers: array[0..3] of TNumber;
a, b, c, d: Integer;
s: string;
begin
Numbers[0] := '1';
Numbers[1] := '8';
Numbers[2] := '7';
Numbers[3] := '2';
for a := low(Numbers) to High(Numbers) do
for b := low(Numbers) to High(Numbers) do
for c := low(Numbers) to High(Numbers) do
for d := low(Numbers) to High(Numbers) do
begin
s := Numbers[a] + Numbers[b] + Numbers[c] + Numbers[d];
if
(Occurrences('1', s) > 1 ) or
(Occurrences('8', s) > 1 ) or
(Occurrences('7', s) > 1 ) or
(Occurrences('2', s) > 1 )
then
Continue
else
Memo1.Lines.Add(s);
end;
end;
function TForm1.Occurrences(const Substring, Text: string): Integer;
var
Offset: Integer;
begin
Result := 0;
Offset := PosEx(Substring, Text, 1);
while Offset <> 0 do
begin
Inc(Result);
Offset := PosEx(Substring, Text, offset + length(Substring));
end;
end;
end.
Here is some code that produces the output you desire. You'd need to work it around a bit for your needs, but the concept expressed in this recursive solution is the important thing:
program Permuatations;
{$APPTYPE CONSOLE}
type
TElements = '1'..'3';
procedure EnumerateCombinations(const Stem: string; Len: Integer);
var
i: Integer;
el: TElements;
Used: set of TElements;
begin
if Len=0 then
exit;
Used := [];
for i := 1 to Length(Stem) do
Include(Used, Stem[i]);
for el := low(el) to high(el) do
begin
if el in Used then
continue;
if Len=1 then
Writeln(Stem+el)
else
EnumerateCombinations(Stem+el, Len-1)
end;
end;
procedure Main;
begin
EnumerateCombinations('', 1+ord(high(TElements))-ord(low(TElements)));
end;
begin
Main;
Readln;
end.
Output:
123
132
213
231
312
321
If you change the definition of TElements, for example to '1'..'4' then you will see the 24 possible permutations.

Resources