Reading two dimensional pl/sql array - oracle

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

Related

TOP with index variable oracle

I was trying to use the variable 'ind' to get the ROWNUM on my select, but everytime I try to use the variable there I get a error like:
ORA-01008: not all variables bound
or these two:
ORA-01403: no data found
ORA-06512: at line 10
DECLARE
texto VARCHAR2(255);
ind NUMBER := 0;
BEGIN
LOOP
ind := ind + 1;
IF ind > 3 THEN
EXIT;
END IF;
SELECT TEXTO_LOG
INTO texto
from table WHERE REGEXP_LIKE(TEXTO_LOG, 'Alteração') AND ROWNUM >= :ind AND ROWNUM <= :ind ;
dbms_output.put_line(substr(trim(texto), 1, instr(texto, ' ')));
dbms_output.put_line(substr(texto, 0, 100));
END LOOP;
END;
/
I searched and found someone telling that not all variables bound is a bug, I'm not sure if it's.
I tried the ROWNUM with different opperators. Any suggestions?
Usage of rownum is the problem here apart from other issues already answered. a predicate like rownum>=2 and rownum <=2 (and so on...till exit point) yield no result and thus no_data_found error
But as workaround put the rownum inside from clause and restrict it outside should work,
DECLARE
texto VARCHAR2(255);
ind NUMBER := 0;
BEGIN
LOOP
ind := ind + 1;
IF ind > 3
THEN
EXIT;
END IF;
SELECT texto_log
INTO texto
FROM (SELECT texto_log
,rownum myrownum
FROM TABLE
WHERE regexp_like(texto_log
,'Alteração'))
WHERE myrownum >= ind
AND myrownum <= ind;
dbms_output.put_line(substr(TRIM(texto)
,1
,instr(texto
,' ')));
dbms_output.put_line(substr(texto
,0
,100));
END LOOP;
END;
/
The error is that you are referring to :ind as if it were a bind variable, when it is not. It is in fact a variable declared in your DECLARE section.
You might try this
** Update **
As your query looks like it is faling, the reason perhaps is in the query itself. Run this and get the output and running separately
set serveroutput on size unlimited
DECLARE
texto VARCHAR2(255);
ind NUMBER := 0;
BEGIN
for r in 1..4
LOOP
ind := r + 1;
dbms_output.put_line ( q'[SELECT TEXTO_LOG
INTO texto
from table WHERE REGEXP_LIKE(TEXTO_LOG, 'Alteração') AND ROWNUM <= ind ;
dbms_output.put_line(substr(trim(texto), 1, instr(texto, ' ')));
dbms_output.put_line(substr(texto, 0, 100));]');
exit when ind > 3;
END LOOP;
END;
/
Although you can build it like this which is easier
DECLARE
texto VARCHAR2(255);
ind NUMBER := 0;
BEGIN
for r in 1..4
LOOP
ind := r + 1;
dbms_output.put_line(ind);
SELECT TEXTO_LOG
INTO texto
from table WHERE REGEXP_LIKE(TEXTO_LOG, 'Alteração') AND ROWNUM >= ind AND ROWNUM <= ind ;
dbms_output.put_line(substr(trim(texto), 1, instr(texto, ' ')));
dbms_output.put_line(substr(texto, 0, 100));
exit when ind > 3;
END LOOP;
END;
/
EXample
SQL> DECLARE
texto VARCHAR2(255);
ind NUMBER := 0;
BEGIN
for r in 1..4
LOOP
ind := r + 1;
dbms_output.put_line(ind);
exit when ind > 3;
END LOOP;
END;
/ 2 3 4 5 6 7 8 9 10 11 12
2
3
4
PL/SQL procedure successfully completed.
SQL>
With implicit cursor
DECLARE
-- texto VARCHAR2(255);
ind NUMBER := 0;
BEGIN
FOR i IN (SELECT TEXTO_LOG FROM table WHERE REGEXP_LIKE(TEXTO_LOG, 'Alteração'))
LOOP
ind:=ind+1;
EXIT WHEN ind >3;
DBMS_OUTPUT.PUT_LINE(SUBSTR(TRIM(i.TEXTO_LOG), 1, INSTR(i.TEXTO_LOG, ' ')));
DBMS_OUTPUT.PUT_LINE(SUBSTR(i.TEXTO_LOG, 0, 100));
END LOOP;
END;

PLSQL (finding range of prime number to 1000 )

DECLARE
n NUMBER;<br>i NUMBER;
pr NUMBER;
BEGIN
FOR n IN 2 .. 1000 LOOP
pr := 1;
FOR i IN 2 .. n / 2 LOOP
IF MOD(n, i) = 0 THEN
pr := 0;
END IF;
END LOOP;
IF (N = 997) THEN
DBMS_OUTPUT.PUT(n);
pr:=2;
ELSE
IF pr = 1 THEN
DBMS_OUTPUT.PUT(n||'&');
END IF;
END if;
END LOOP;
dbms_output.new_line;
END;
output should be as in one line----> 2&3&5&7&11&13&17&19&23&29&31&37&41&43&47&53&59&61&67&71&73&79&83&89&97&101&103&107&109&113&127&131&137&139&149&151&157&163&167&173&179&181&191&193&197&199&211&223&227&229&233&239&241&251&257&263&269&271&277&281&283&293&307&311&313&317&331&337&347&349&353&359&367&373&379&383&389&397&401&409&419&421&431&433&439&443&449&457&461&463&467&479&487&491&499&503&509&521&523&541&547&557&563&569&571&577&587&593&599&601&607&613&617&619&631&641&643&647&653&659&661&673&677&683&691&701&709&719&727&733&739&743&751&757&761&769&773&787&797&809&811&821&823&827&829&839&853&857&859&863&877&881&883&887&907&911&919&929&937&941&947&953&967&971&977&983&991&997
but not working in hackerrank compiler question is "Print Prime Numbers"
There's no problem in your code to produce the desired string except <br>i NUMBER;
Just comment out that piece in the declaration section as below :
DECLARE
n NUMBER; -- <br>i NUMBER;
pr NUMBER;
Here's a Demo for it.

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

confused between dbms_output.put_line and dbms_output.put pl/sql

i was trying to make something like this
when input : 5
it will print
A B C D E
input : 10
print
A B C D E
J I H G F
input : 15
print
A B C D E
J I H G F
K L M N O
input : 20
A B C D E
J I H G F
K L M N O
T S R Q P
and so on...
here is my code i create
declare
angka number := '&Angka';
i number := trunc(angka/5);
p number := 65;
a number := 1;
b number := 1;
begin
while a <= b loop
if mod(i,2) = 1 then
a := 5;
for b in 1..5 loop
p := p + a
dbms_output.put( chr(p) || ' ' );
a := a - 1;
end loop;
p := p + 5;
else
a := 1;
for b in 1..5 loop
p := p + a
dbms_output.put( chr(p) || ' ' );
a := a + 1;
end loop;
end loop;
dbms_output.put_line(' ');
end;
/
but i was still confused it's still didn't work
and about dbms_output.put_line vs dbms_output.put can someone explain this ? because i was trying print using dbms_output.put it's didn't show.. i don't know why
Thanks
Firstly, the line p := p + a has not been terminated by semi-colon. Ideally, the PL/SQL anonymous block shouldn't compile at first place.
Secondly, with PUT procedure, you haven't completed the line yet. It needs GET_LINES to retrieve an array of lines from the buffer.
There was a similar question, Is dbms_output.put() being buffered differently from dbms_output.put_line()?
You have some problems in your code. I don't believe that you can execute exactly this code. Propably, you forgot to copy some parts of it.
First of all, syntax errors:
declare
angka number := '&Angka';
i number := trunc(angka/5);
p number := 65;
a number := 1;
b number := 1;
begin
while a <= b loop
if mod(i,2) = 1 then
a := 5;
for b in 1..5 loop
p := p + a -- ";" missed
dbms_output.put( chr(p) || ' ' );
a := a - 1;
end loop;
p := p + 5;
else
a := 1;
for b in 1..5 loop
p := p + a -- ";" missed
dbms_output.put( chr(p) || ' ' );
a := a + 1;
end loop;
-- here you missed "end if"
end loop;
dbms_output.put_line(' ');
end;
/
Also you don't need your outer loop ("while a <= b loop"), because its condition always is true and code execution will never ends. And last - when you declare
for b in 1..5 loop
oracle creates here new variable with name "b", and inside the loop previously declared b is not visible. Try to execute this:
declare
b number := 111;
begin
for b in 1..5 loop
dbms_output.put_line(b);
end loop;
dbms_output.put_line(b);
end;
/
You will get:
1
2
3
4
5
111
If you correct these errors, your code will work as you want.

factorial of a number in pl/sql

The following pl/sql program generates an error on execution on line the sum :=temp*sum; encountered symbol ; when expecting ( . Please explain my mistake.
declare
n number;
temp number;
sum number := 1;
begin
n := &n;
temp := n;
while temp>0 loop
sum := temp*sum;
temp := temp-1;
end loop;
dbms_output.put_line('Factorial of '||n||' is '||sum);
end;
/
Maybe not the answer to your question, but there is no need for PL/SQL here:
select round(exp(sum(ln(level))))
from dual
connect by level <= 5;
where 5 is your number (5!).
Additionally, if you like to operate faster in PL/SQL use pls_integer instead of number.
UPDATE
So according to comments I felt free to test:
create or replace package test_ is
function by_query(num number) return number deterministic;
function by_plsql(num number) return number deterministic;
end test_;
/
create or replace package body test_ is
function by_query(num number) return number deterministic
is
res number;
begin
select round(exp(sum(ln(level))))
into res
from dual
connect by level <= num;
return res;
end;
function by_plsql(num number) return number deterministic
is
n number := 0;
begin
for i in 1..num loop
n := n + ln(i);
end loop;
return round(exp(n));
end;
end test_;
So there are two functions with different content. Test query:
declare
dummy number;
begin
for i in 1..10000 loop
dummy := test_.by_query(5);
end loop;
end;
0.094 sec.
declare
dummy number;
begin
for i in 1..10000 loop
dummy := test_.by_plsql(5);
end loop;
end;
0.094 sec.
You'll say I am cheater and using deterministic keyword but here it is obvious and is needed by logic. If I remove it, the same scripts are working 1.7 sec vs 1.3 sec, so procedure is only a bit faster, there is no even double-win in performance. The totally opposite effect you will get if you use the function in a query so it is a fair trade.
Sum is reserved word in sql. Change variable name like
declare
n number;
temp number;
sum_ number := 1;
begin
n := &n;
temp := n;
while temp>0 loop
sum_ := temp*sum_;
temp := temp-1;
end loop;
dbms_output.put_line('Factorial of '||n||' is '||sum_);
end;
/
declare
n number;
i number;
sum_of_log_10s number;
exponent number;
base number;
begin
n := &n;
i := 1;
sum_of_log_10s := 0;
while i <= n loop
-- do stuff
sum_of_log_10s := sum_of_log_10s + log(10,i);
i := i + 1;
end loop;
dbms_output.put_line('sum of logs = '||sum_of_log_10s);
exponent := floor(sum_of_log_10s);
base := power(10,sum_of_log_10s - exponent);
dbms_output.put_line(n||'! = '||base||' x 10^'||exponent);
end;
I came up with this code that I like even better than #smnbbrv's answer. It's a great way to check the speed of a machine. I've been using a variation of this since my Atari 800
ALTER SESSION FORCE PARALLEL DDL PARALLEL 16;
ALTER SESSION FORCE PARALLEL DML PARALLEL 16;
ALTER SESSION FORCE PARALLEL QUERY PARALLEL 16;
with t as (
select /*+materialize*/
rownum i
from dual connect by rownum < 100000 -- put number to calculate n! here
)
,t1 as (
select /*+parallel(t,16)*/ /*+materialize*/
sum(log(10,i)) logsum
from t
)
select
trunc(power(10,(mod(logsum,1))),3) ||' x 10^'||trim(to_char(floor(logsum),'999,999,999,999')) factorial
-- logsum
from t1
;
-- returns 2.824 x 10^456,568
Here is the simple code for finding factorial of number at run time...
declare
-- it gives the final answer after computation
fac number :=1;
-- given number n
-- taking input from user
n number := &1;
-- start block
begin
-- start while loop
while n > 0 loop
-- multiple with n and decrease n's value
fac:=n*fac;
--dbms_output.put(n||'*');
n:=n-1;
end loop;
-- end loop
-- print result of fac
dbms_output.put_line(fac);
-- end the begin block
end;

Resources