Associative array issue - oracle

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

Related

Comparing data of any type without overloading

let's start with an example:
type Collection_t is table of varchar2(3);
Collection_v Collection_t := Collection_t('qwe', 'asd', 'yxc', 'rtz', 'fgh', 'vbn');
single_var varchar2(3) := 'yxc';
procedure get_position(Single_Value varchar2, Value_Set Collection_t) is
i integer := 1;
begin
while (i is not null) loop
if Single_Value = Value_Set(i)
then
dbms_output.put_line(i);
end if;
i := Value_Set.Next(i);
end loop;
end;
begin
get_position(single_var, Collection_v);
end;
now, question is: can I declare this procedure with 'anydata', and check if table (2ed argument) consists of the same type as first argument.
I'd assume declaration of a procedure would look like that:
procedure get_position(Single_Value anydata, Value_Set anydata) is ...
later I'd compare types, and honestly I couldn't figure it out, how to solve this problem.
From my limited understanding, you still have to encode/decode anydata into basic (or user-defined) PL/SQL types to do anything meaningful like comparing values, so you might not gain the benefits of dynamic languages like Python.
Here is an example, passing anydata as a parameter. You'll need to update anydata_to_varchar to handle data types you need.
Personally, overloading seems like a more straightforward approach, unless there is a better way to work with anydata values.
declare
type tab_anydata is table of anydata;
-- test as varchar2
/*
lookup_array tab_anydata := tab_anydata(
anydata.convertVarchar2('blah'),
anydata.convertVarchar2('meh'),
anydata.convertVarchar2('foo'),
anydata.convertVarchar2('bar')
);
lookup_value anydata := anydata.convertVarchar2('foo');
*/
-- test as date
lookup_array tab_anydata := tab_anydata(
anydata.convertDate(trunc(sysdate - 2)),
anydata.convertDate(trunc(sysdate - 0)),
anydata.convertDate(trunc(sysdate + 1)),
anydata.convertDate(trunc(sysdate + 2))
);
lookup_value anydata := anydata.convertDate(trunc(sysdate));
function anydata_to_varchar(p_what anydata)
return varchar2
is
value_type varchar2(30) := anydata.GetTypeName(p_what);
result varchar2(32767);
begin
select
case value_type
when 'SYS.VARCHAR2' then anydata.AccessVarchar2(p_what)
when 'SYS.DATE' then to_char(anydata.AccessDate(p_what), 'YYYY-MM-DD')
when 'SYS.NUMBER' then to_char(anydata.AccessNumber(p_what))
else null
end into result
from dual;
return result;
end;
function get_position(p_what anydata, p_where tab_anydata)
return number
is
pos number := -1;
what_value varchar2(30) := anydata_to_varchar(p_what);
curr_value varchar2(30);
begin
for i in 1..p_where.count
loop
curr_value := anydata_to_varchar(p_where(i));
if what_value = curr_value then
pos := i;
exit;
end if;
end loop;
return pos;
end;
begin
dbms_output.put_line('lookup type : '||anydata.GetTypeName(lookup_value));
dbms_output.put_line('lookup value : '||anydata_to_varchar(lookup_value));
dbms_output.put_line('found position: '||get_position(lookup_value, lookup_array));
end;
/
dbms_output:
lookup type : SYS.DATE
lookup value : 2022-07-20
found position: 2
db<>fiddle here

PLSQL Get Variable By Loop Index

I am trying to reach columns by loop index of a cursor record. Currently i am using multiple variables for each columns thus I think that I should refactor my codes. In java, I'd use reflection to do that but I stuck in PLSQL. Code will explain better
input is passed into from loop.
i_member_awd_rowtype in member_awd%rowtype
.
.
.
--many more inputs
l_step1_company := i_member_awd_rowtype.flt_company;
l_step1_subclass := i_member_awd_rowtype.class_code;
l_step2_company := i_member_awd_rowtype.ret_flt_company;
l_step2_subclass := i_member_awd_rowtype.ret_class_code;
l_step3_company := i_member_awd_rowtype.step3_company;
l_step3_subclass := i_member_awd_rowtype.step3_class_code;
l_step4_company := i_member_awd_rowtype.step4_company;
l_step4_subclass := i_member_awd_rowtype.step4_class_code;
l_step5_company := i_member_awd_rowtype.step5_company;
l_step5_subclass := i_member_awd_rowtype.step5_class_code;
l_step6_company := i_member_awd_rowtype.step6_company;
l_step6_subclass := i_member_awd_rowtype.step6_class_code;
l_step7_company := i_member_awd_rowtype.step7_company;
l_step7_subclass := i_member_awd_rowtype.step7_class_code;
l_step8_company := i_member_awd_rowtype.step8_company;
l_step8_subclass := i_member_awd_rowtype.step8_class_code;
I need to assign single class, company and subclass variables in a loop such as
/*for i in 1 .. 8 loop
l_step_subclass :=
end loop;*/
Is there any way to write as I wanted in PLSQL? Thanks.
The following code block containing a Dynamic SQL statement might be used, assuming you wanna gather the records for each identity column(id) of the table :
SQL> set serveroutput on
SQL> declare
v_tbl varchar2(31) := 'member_awd';
v_sql varchar2(250);
v_id member_awd.id%type := :p_id;
type typ is table of varchar2(32767) index by binary_integer;
l_step_subclass typ;
begin
for c in ( select column_id, column_name
from user_tab_columns
where table_name = upper(v_tbl) order by column_id )
loop
v_sql := 'select '||c.column_name||' from '||v_tbl||' where id = :i_id ';
execute immediate v_sql into l_step_subclass(c.column_id) using v_id;
dbms_output.put_line(l_step_subclass(c.column_id));
end loop;
end;
/
where the variable l_step_subclass is converted to the array type. This way, all values for each individual column are assigned to this column local variable.

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.

How to change the subscript/index value in an associative array?

Is it possible to change the subscript/index value of an existing element in an associative array?
declare
type a_arr is table of varchar2(20) index by pls_integer;
tb1 a_arr;
begin
tb1(1) := 'aaaa';
tb1(2) := 'bbbb';
tb1(3) := 'cccc';
end;
/
In the above associative array tb1, is it possible to change the subscript value from 1 to 10 (ie from tb1(1) to tb1(10)) without deleting or creating a new element in the table?
It is unclear what are you trying to do. Here's basic general example. The output is 'aaaa' 10 times. You can add some logic in between. For example, if i = 3 then tbl_val:= 'bbbb' or smth lk this. You can also parameterise the start and/or end loop boundaries if you create a procedure for example.
DECLARE
type a_arr is table of varchar2(20) index by pls_integer;
tb1 a_arr;
tbl_val VARCHAR2(20):= 'aaaa';
BEGIN
FOR i IN 1..10 LOOP
tb1(i):= tbl_val;
dbms_output.put_line(tb1(i));
END LOOP;
END;
/

Wrong number or TYPES of arguments, error in PL/SQL

I have to create a list of RECORD and I need to send it to a procedure.
There is my header.
CREATE OR REPLACE PACKAGE tema4 IS
TYPE obj IS RECORD(id INTEGER := 0,percent INTEGER := 0);
TYPE listObj IS TABLE OF obj INDEX BY PLS_INTEGER;
PROCEDURE ex1 (p_listObj IN listObj);
END tema4;
My body.
create or replace PACKAGE BODY tema4 IS
PROCEDURE ex1 (p_listObj IN listObj) IS
BEGIN
DBMS_OUTPUT.PUT_LINE('Cant reach');
END ex1;
END tema4;
And my code that calls procedure ex1.
DECLARE
TYPE obj IS RECORD(id INTEGER := 0,percent INTEGER := 0);
TYPE listObj IS TABLE OF obj INDEX BY PLS_INTEGER;
v_obj obj;
v_listObj listObj;
BEGIN
FOR v_i IN (SELECT ID,BURSA FROM STUDENTI ORDER BY ID) LOOP
v_obj.id := v_i.id;
v_obj.percent := 50;
v_listObj(v_i.id) := v_obj;
END LOOP;
FOR v_i IN v_listObj.FIRST..v_listObj.LAST LOOP
DBMS_OUTPUT.PUT_LINE(v_listObj(v_i).id || ' - ' ||
v_listObj(v_i).percent);
END LOOP;
tema4.ex1(v_listObj); --this line is with problems
END;
PLS-00306: wrong number or types of arguments in call to 'EX1'
Can someone explain me what is wrong in my code? I also tried to create my type as global, but it won't let me because of 'RECORD' keyword.
Don't declare the types again (new types), use the types already declared in the package spec:
DECLARE
v_obj tema4.obj;
v_listObj tema4.listObj;
BEGIN
FOR v_i IN (SELECT ID,BURSA FROM STUDENTI ORDER BY ID) LOOP
v_obj.id := v_i.id;
v_obj.percent := 50;
v_listObj(v_i.id) := v_obj;
END LOOP;
FOR v_i IN v_listObj.FIRST..v_listObj.LAST LOOP
DBMS_OUTPUT.PUT_LINE(v_listObj(v_i).id || ' - ' ||
v_listObj(v_i).percent);
END LOOP;
tema4.ex1(v_listObj); --this line is with problems
END;

Resources