Oracle PL/SQL Bubble-Sorting - ORA-01403: no data found ORA-06512: at line 12 - oracle

Here is the code:
declare
p_arr dbms_sql.Number_Table;
i pls_integer;
procedure do_sort(p_arr in out dbms_sql.Number_Table, p_asc in boolean default null, p_nulls_last in boolean default null) is
x pls_integer;
p_temp number;
begin
for i in 1..p_arr.COUNT-1
loop
for x in 2..p_arr.COUNT
loop
if p_arr(x) < p_arr(x-1)
then
p_temp := p_arr(x-1);
p_arr(x-1) := p_arr(x);
p_arr(x) := p_temp;
end if;
end loop;
end loop;
return;
end;
begin
p_arr(-1) := 0;
p_arr(0) := -2;
p_arr(1) := 10.1;
p_arr(2) := null;
p_arr(3) := 10.1;
p_arr(4) := -1;
do_sort(p_arr);
i := p_arr.first;
while i is not null loop
dbms_output.put_line('arr('||i||') = '||nvl(to_char(p_arr(i)), 'null')||';');
i := p_arr.next(i);
end loop;
end;
It gives me an error on line 12 - "No data found".
Respectively, the procedure "do_sort" on line 29 also fails.
Seems like the problem with nested loop, which I can't figure out for now.
When there is only "first-level" loop with some code in it, such as assigning new values to collection - it performs well.
Sorting block outside of procedure body also works.
Thanks in advance.

You're filling your number table with specific indexes:
p_arr(-1) := 0;
p_arr(0) := -2;
p_arr(1) := 10.1;
p_arr(2) := null;
p_arr(3) := 10.1;
p_arr(4) := -1;
But when you loop you are using index values from 1 to the count of elements, which is 6. There is no element with index 5 or 6, and when you try to refer to p_arr(5) there is no such element - hence the error. And you miss out those with indexes -1 and 0.
It works if you re-index your initial values:
p_arr(1) := 0;
p_arr(2) := -2;
p_arr(3) := 10.1;
p_arr(4) := null;
p_arr(5) := 10.1;
p_arr(6) := -1;
which then gets output:
arr(1) = -2;
arr(2) = 0;
arr(3) = 10.1;
arr(4) = null;
arr(5) = -1;
arr(6) = 10.1;
PL/SQL procedure successfully completed.
Notice what happens with your null value though... you cannot compare null with anything else, so p_arr(x) < p_arr(x-1) is undefined (but not true) when the null element is evaluated on both sides of that comparison. So, it doesn't move. You would need to decide where you want nulls to end up to determine how to modify the code to achieve that.
If you have a specific reason for starting your indexing at -1 instead of 1, you could still do that, and change the references inside your loop to be p_arr(x+2) etc., but it would be more confusing and error-prone. Or you coudl change your loop ranges to handle that instead:
for i in -1..p_arr.COUNT - 1 -- 2 less than previously, on each end of range
loop
for x in 0..p_arr.COUNT - 2 -- 2 less than previously, on each end of range
loop
... which gets the same result, using your original table population starting from index -1. Oracle Live SQL demo.
The indexes used inside the loops have to align with the indexes you use to populate the table, however you do it.

Related

inserting of data not happening in oracle

I am new to plsql.I have a table where i need to insert the data(some dummy data).So,i thought to use plsql block and using For loop it will insert the data automatically.The plsql block is runned successfully,but the data are stored as empty.The block I tried is:
declare
v_number1 number;
v_number2 number;
v_number3 number;
begin
For Lcntr IN 2..17
LOOP
v_number1 := v_number1+1;
v_number2 := v_number2+2;
v_number3 := v_number3+3;
Insert into stu.result(res_id,stu_id,eng,maths,science) values (stu.seq_no.NEXTVAL,Lcntr,v_number1,v_number2,v_number3);
END LOOP;
end;
But my table is loaded as:(please ignore first two row data,i inserted it manually):
The data for eng,maths,science is not being inserted.why it is happening so?
That's because your variables are NULL. NULL + 1 = NULL as well.
If you modify declaration to
v_number1 number := 0;
v_number2 number := 0;
v_number3 number := 0;
something might happen.

Why I cant delete element from collection (array) PLSQL

At this handler I delete NULL element:
if p_arr(i) is null then
p_arr.delete(p_arr(i));
end if;
but null element still in collection. How can I correct this?
The task is to sort elements in collection, but the condition is that there can be NULL in collection. I should delete them.
declare
p_arr dbms_sql.Number_Table;
i pls_integer;
procedure do_sort(p_arr in out dbms_sql.Number_Table, p_asc in boolean
default null, p_nulls_last in boolean default null) is
x pls_integer;
p_temp number;
begin
for i in -1..p_arr.COUNT - 2
loop
if p_arr(i) is null then
p_arr.delete(p_arr(i));
end if;
end loop;
end;
begin
p_arr(-1) := 0;
p_arr(0) := -2;
p_arr(1) := 10.1;
p_arr(2) := null;
p_arr(3) := 10.1;
p_arr(4) := -1;
do_sort(p_arr);
i := p_arr.first;
while i is not null loop
dbms_output.put_line('arr('||i||') = '||nvl(to_char(p_arr(i)),
'null')||';');
i := p_arr.next(i);
end loop;
end;
That's because you are passing the element itself as the argument to the delete, rather than the index
p_arr.delete(p_arr(i)) is equivalent to p_arr.delete(NULL) - So it simply doesn't delete anything.
So, change it to p_arr.DELETE(i) it will work.

Associative array issue

I have created an associative array, I understand it can be used different way of writing but however just need tips how to make this work. Currently when I compile this block I would receive no data found. Thank you!
DECLARE
TYPE type_state IS TABLE OF VARCHAR(50)
INDEX BY VARCHAR2(50);
tbl_state type_state;
lv_statecity1_txt VARCHAR2(30):= 'TAMPA';
lv_statecity2_txt VARCHAR2(30):= 'ATLANTA';
lv_statecity3_txt VARCHAR2(30):= 'NYC';
lv_cnt_num NUMBER(5) := 0;
BEGIN
tbl_state('FLORIDA') := lv_statecity1_txt;
tbl_state('GEORGIA') := lv_statecity2_txt;
tbl_state('New_York') := lv_statecity3_txt;
FOR i IN 1..tbl_state.count loop
IF tbl_state(i) IS NOT NULL THEN
LV_CNT_NUM := LV_CNT_NUM + 1;
dbms_output.put_line(tbl_state(i));
END IF;
END LOOP;
dbms_output.put_line('That''s it folks');
END;
tbl_state is a table of strings indexed by strings - passing in index values 1, 2, 3 (numbers) won't work.
It is true that array pairs are still ordered (first, second etc.), but accessing them in a loop is a bit more complicated. You will need a WHILE loop, and the index (I kept the name i to match your code as closely as possible) must be declared to be the same data type and length as the keys in the array.
DECLARE
TYPE type_state IS TABLE OF VARCHAR(50)
INDEX BY VARCHAR2(50);
tbl_state type_state;
lv_statecity1_txt VARCHAR2(30):= 'TAMPA';
lv_statecity2_txt VARCHAR2(30):= 'ATLANTA';
lv_statecity3_txt VARCHAR2(30):= 'NYC';
lv_cnt_num NUMBER(5) := 0; -- WHAT IS THIS FOR? NEEDED??
i varchar2(50); -- Notice this line
BEGIN
tbl_state('FLORIDA') := lv_statecity1_txt;
tbl_state('GEORGIA') := lv_statecity2_txt;
tbl_state('New_York') := lv_statecity3_txt;
i := tbl_state.first; -- And this line
while (i is not null) loop -- And this one
LV_CNT_NUM := LV_CNT_NUM + 1;
dbms_output.put_line(tbl_state(i));
i := tbl_state.next(i); -- And this one
END LOOP;
dbms_output.put_line('That''s it folks');
END;
/

How do I fix "numeric or value error" message?

I have been stuck with this issue now all morning. I actually saw this code here and decide to use it for our purpose here.
The issue that I am running into is that when we execute the code, sometimes it writes a file from db to the folder.
Other times, we get "numeric or value error"
Can any expert please help me fix it?
Here is the code I am using:
create or replace
PROCEDURE getfile(pfname VARCHAR2, display_name IN VARCHAR2)
IS
vblob BLOB;
vstart NUMBER := 1;
bytelen NUMBER := 32000;
len NUMBER;
my_vr RAW(32000);
x NUMBER;
v_name VARCHAR2(32760);
lv_str_len NUMBER;
l_output utl_file.file_type;
BEGIN
-- define output directory
--lv_str_len := Length(pfname);
--v_name := display_name||upper(substr(pfname,lv_str_len-3,lv_str_len));
v_name := display_name;
l_output := utl_file.Fopen('My_DIR', v_name, 'w', 32760);
-- get length of blob
SELECT dbms_lob.Getlength(FILENAME)
INTO len
FROM GENERAL.GUBFILE
WHERE gubfile_name = pfname;
-- dbms_output.put_line('Length: '||len);
-- save blob length
x := len;
-- select blob into variable
SELECT BLOBVALUE
INTO vblob
FROM FILES
WHERE filename = pfname;
-- if small enough for a single write
IF len < 32760 THEN
-- dbms_output.put_line('Single write ');
utl_file.Put_raw(l_output, vblob);
utl_file.Fflush(l_output);
ELSE -- write in pieces
-- dbms_output.put_line('multi write '||vstart);
vstart := 1;
WHILE vstart < len LOOP
dbms_lob.READ(vblob, bytelen, vstart, my_vr);
utl_file.Put_raw(l_output, my_vr);
utl_file.Fflush(l_output);
-- set the start position for the next cut
vstart := vstart + bytelen;
-- set the end position if less than 32000 bytes
x := x - bytelen;
IF x < 32000 THEN
bytelen := x;
END IF;
END LOOP;
END IF;
dbms_output.Put_line('End');
utl_file.Fclose(l_output);
END getfile;
The exact error is:
ORA-06502: PL/SQL: numeric or value error
ORA-06512: at "USER.GETFILE", line 40
ORA-06512: at line 8
The error comes from utl_file.put_raw.
The maximum size of the buffer parameter is 32767 bytes.
You check for IF len < 32760 THEN, however, I see no guarantee in your code, that the len variable actually holds the length of the vblob variable that is the buffer in the put_raw call.
So I suppose the vblob variable's actual length is longer then 32767 and that is the reason for the error.
Hence I suggest to delete this piece of code:
IF len < 32760 THEN
-- dbms_output.put_line('Single write ');
utl_file.Put_raw(l_output, vblob);
utl_file.Fflush(l_output);
ELSE
also the END IF; of course, and always go for the 'write in pieces' branch.
I see now, you've done this based on the Burleson example which is good http://www.dba-oracle.com/t_writing_blob_clob_os_file.htm
but you see, unlike you, Burleson gets the len variable and the vblob variable from the same table and the same field.
-- get length of blob
SELECT dbms_lob.getlength(productblob)
INTO len
FROM products
WHERE id = product_id;
-- save blob length
x := len;
-- select blob into variable
SELECT product_blob
INTO vblob
FROM products
WHERE id = product_id;
EDIT
So an other option would be to fix the select for getting length. This means you'll have to replace this select:
-- get length of blob
SELECT dbms_lob.Getlength(FILENAME)
INTO len
FROM GENERAL.GUBFILE
WHERE gubfile_name = pfname;
with this:
-- get length of blob
SELECT dbms_lob.Getlength(BLOBVALUE)
INTO len
FROM FILES
WHERE filename = pfname;

PLSQL Collections - how to use table of records?

I'm new to PL/SQL and I'm trying to use a table of records, but I don't know how to use this feature. What is the problem?
DECLARE
TYPE TIP
IS
RECORD
(
F1 SMALLINT,
F2 SMALLINT);
TYPE Ve
IS
TABLE OF TIP;
v ve;
IND SMALLINT := 0;
BEGIN
WHILE(IND<20)
LOOP
IND := IND + 1;
V(IND).F2 := IND-1;
V(IND).F2 := IND;
END LOOP;
END;
What I'm doing wrong?
06531. 00000 - "Reference to uninitialized collection"
You need to make two changes.
v ve := ve();
This initializes the V array. This will create an empty VE table.
IND := IND + 1;
v.extend(IND+1);
V(IND).F2 := IND-1;
V(IND).F2 := IND;
Next is the call to v.EXTEND() to make sure the table has enough entries to hold your values. This now functions correctly.

Resources