whenever users pass a list of values then we need to pause "in" condition.
the jin_son_doc will be like this "India,American Samoa"
create or replace PROCEDURE test_attendee (
out_chr_err_code OUT VARCHAR2,
out_chr_err_msg OUT VARCHAR2,
out_attendee_tab OUT return_attendee_arr_result,
in_json_doc IN VARCHAR2
) IS
l_chr_srcstage VARCHAR2(200);
l_chr_biqtab VARCHAR2(200);
l_chr_srctab VARCHAR2(200);
l_chr_bistagtab VARCHAR2(200);
l_chr_err_code VARCHAR2(255);
l_chr_err_msg VARCHAR2(255);
l_out_chr_errbuf VARCHAR2(2000);
lrec return_attendee_report;
l_num_counter NUMBER := 0;
json_doc CHAR_ARRAY(1000) := in_json_doc;
CURSOR cur_attendee_data IS
SELECT
*
FROM
(
SELECT
a.*,
ROWNUM rn
FROM
(SELECT * FROM (
SELECT
r.id request_id,
c.designation ext_att_title,
DECODE(c.attendee_type, 'externalattendees', 'External', 'Internal') attendee_type
FROM
bi_request r
LEFT JOIN bi_request_activity_day a ON a.request_id = r.id
LEFT JOIN bi_request_catering_activity b ON b.request_activity_day_id = a.id
LEFT JOIN bi_request_attendees c ON c.request_id = r.id
LEFT JOIN bi_request_act_day_room d ON d.request_activity_day_id = a.id
AND d.room = b.room
WHERE
r.state = 'CONFIRMED'
AND a.event_date BETWEEN l_start_date AND l_end_date
AND r.location_id = (
SELECT UNIQUE
( id )
FROM
bi_location
WHERE
unique_id = l_location_id
)
AND d.room_type = 'MAIN_ROOM'
AND country IN (
SELECT
column_value
FROM
TABLE ( json_doc )
)
)
WHERE
1=1
) a
WHERE
ROWNUM <= l_end_row
)
WHERE
rn >= l_start_row;
TYPE rec_attendee_data IS
TABLE OF cur_attendee_data%rowtype INDEX BY PLS_INTEGER;
l_cur_attendee_data rec_attendee_data;
BEGIN
dbms_output.put_line(l_country_array.count);
out_attendee_tab := return_attendee_arr_result();
OPEN cur_attendee_data;
LOOP
FETCH cur_attendee_data BULK COLLECT INTO l_cur_attendee_data;
EXIT WHEN l_cur_attendee_data.count = 0;
dbms_output.put_line('here in first insert');
lrec := return_attendee_report();
out_attendee_tab := return_attendee_arr_result(return_attendee_report());
out_attendee_tab.DELETE;
FOR i IN 1..l_cur_attendee_data.count LOOP
-- dbms_output.put_line('Inside cursor ' );
BEGIN
l_num_counter := l_num_counter + 1;
lrec := return_attendee_report();
lrec.requestid := l_cur_attendee_data(i).request_id;
lrec.attendeetype := l_cur_attendee_data(i).attendee_type;
lrec.attendeetype := json_doc;
IF l_num_counter > 1 THEN
out_attendee_tab.extend();
out_attendee_tab(l_num_counter) := return_attendee_report();
ELSE
out_attendee_tab := return_attendee_arr_result(return_attendee_report());
END IF;
out_attendee_tab(l_num_counter) := lrec;
EXCEPTION
WHEN OTHERS THEN
dbms_output.put_line('Error occurred : ' || sqlerrm);
END;
END LOOP;
END LOOP;
EXCEPTION
WHEN OTHERS THEN
dbms_output.put_line('HERE INSIIDE OTHERS' || sqlerrm);
END;
Whenever j"son_doc" is null we need to skip the in clause. Is this possible, let me know if we have any solution.
user will pass jin_son_doc will be like this "India, America".
by using the following function i'm converting string to array,
create or replace FUNCTION fn_varchar_to_array(p_list IN VARCHAR2)
RETURN CHAR_ARRAY
AS
l_string VARCHAR2(32767) := p_list || ',';
l_comma_index PLS_INTEGER;
l_index PLS_INTEGER := 1;
l_tab CHAR_ARRAY := CHAR_ARRAY();
BEGIN
LOOP
l_comma_index := INSTR(l_string, ',', l_index);
EXIT WHEN l_comma_index = 0;
l_tab.EXTEND;
l_tab(l_tab.COUNT) := SUBSTR(l_string, l_index, l_comma_index - l_index);
l_index := l_comma_index + 1;
END LOOP;
RETURN l_tab;
END fn_varchar_to_array;
You can use OR condition as following:
....
AND (json_doc is null
OR country IN (
SELECT
column_value
FROM
TABLE ( json_doc )
)
)
...
Cheers!!
Well I was writing a trigger and I wanted that the declared variable v_message to append every time the condition is met. So for example if the first two statements are met the v_message should be something like "Invalid account Invalid amount". I must also find a way to separate these two messages by a space if the v_message already contains some sort of an error message as it wont be readable if you had something like this "Invalid accountInvalid amount".
CREATE OR REPLACE TRIGGER checkPayments
BEFORE INSERT ON tbl_payments
FOR EACH ROW
DECLARE
v_message VARCHAR(100 CHAR);
v_is_valid CHAR(1) := 'N';
BEGIN
IF getActiveUser(getOrderUsername(:new.order_id)) = 0
THEN v_message := 'Invalid account';
ELSIF isValidAmount(:new.payment_amount) = 0
THEN v_message := 'Invalid amount';
ELSIF checkOrderExist(:new.order_id) = 0
THEN v_message := 'Invalid order ID';
ELSIF (getValidOrderPayments(:new.order_id) + :new.payment_amount ) > getOrderTotal(:new.order_id)
THEN v_message := 'Payment exceeds total';
ELSE v_message := 'OK' ;
v_is_valid := 'Y';
END IF;
:new.payment_id:= seq_payment_id.nextval;
:new.payment_date:= LOCALTIMESTAMP;
:new.payment_message := v_message;
:new.is_valid := v_is_valid;
END;
/
CREATE OR REPLACE TRIGGER checkPayments
BEFORE INSERT ON tbl_payments
FOR EACH ROW
DECLARE
v_message VARCHAR(100 CHAR);
v_is_valid CHAR(1) := 'N';
BEGIN
v_is_valid := 'Y';
IF getActiveUser(getOrderUsername(:new.order_id)) = 0
THEN v_message := 'Invalid account';
v_is_valid := 'N';
END IF;
IF isValidAmount(:new.payment_amount) = 0
THEN v_message := v_message || ' Invalid amount';
v_is_valid := 'N';
END IF;
IF checkOrderExist(:new.order_id) = 0
THEN v_message := v_message || ' Invalid order ID';
v_is_valid := 'N';
END IF;
IF (getValidOrderPayments(:new.order_id) + :new.payment_amount ) > getOrderTotal(:new.order_id)
THEN v_message := v_message || ' Payment exceeds total';
v_is_valid := 'N';
END IF;
IF v_is_valid = 'Y'
THEN v_message := 'OK' ;
END IF;
:new.payment_id:= seq_payment_id.nextval;
:new.payment_date:= LOCALTIMESTAMP;
:new.payment_message := trim(v_message);
:new.is_valid := v_is_valid;
END;
/
I am getting following error for the stored procedure and not able to understand the issue (must be from db side) While googling, I found similar issues but couldn't get the solution. Can any one help me please find the error in PROCEDURE ??
Error :-
18:58:50,281 ERROR [STDERR] java.sql.SQLException: ORA-06550: line 1, column 7:
PLS-00306: wrong number or types of arguments in call to 'SP_DIST_RETAILER_REMAP'
ORA-06550: line 1, column 7:
PL/SQL: Statement ignored
Stored Prodedure(SP_DIST_RETAILER_REMAP) :-
CREATE OR REPLACE PROCEDURE SMAPRD02.SP_DIST_RETAILER_REMAP (
i_old_dist_code IN VARCHAR2,
i_new_dist_code IN VARCHAR2,
i_territory_remapping IN NUMBER,
i_remapping_reason IN VARCHAR2,
i_trans_doneby_rolename IN VARCHAR2,
i_trans_doneby_id IN NUMBER,
i_trans_dist_rolename IN VARCHAR2,
i_trans_ret_rolename IN VARCHAR2,
i_activity_type IN VARCHAR2,
i_ret_list IN V_ARRAY,
result OUT VARCHAR2,
i_o_query OUT VARCHAR2
)
AS
--i_ret_codes OUT VARCHAR2;
v_dist_count NUMBER;
v_ret_count NUMBER;
v_ret_codes VARCHAR2(10000) := '';
v_flag VARCHAR2(10) := 'true';
v_trans_id NUMBER;
v_query VARCHAR2(10000);
BEGIN
IF i_territory_remapping = 1 then
SELECT count(*) into v_dist_count FROM tblemployee where EMPCODE = i_new_dist_code and circle_code = (select emp.circle_code
from tblemployee emp where emp.empcode = i_old_dist_code) and upper(user_type) like upper('%dist%') and upper(ACCESS_TO) in ('SALES','BOTH') and upper(stage) not in (upper('InActive'));
ELSE
SELECT count(*) into v_dist_count FROM tblemployee where EMPCODE = i_new_dist_code and circle_code = (select emp.circle_code from tblemployee emp
where emp.empcode = i_old_dist_code) and cluster_code = (select emp.cluster_code from tblemployee emp where emp.empcode = i_old_dist_code)
and upper(user_type) like upper('%dist%') and upper(ACCESS_TO) in ('SALES','BOTH') and upper(stage) not in (upper('InActive'));
END IF;
IF v_dist_count =0 THEN
result := 'invalid_new_dist_code';
v_flag := 'false';
ELSIF v_dist_count = 1 THEN
SELECT count(*) into v_ret_count FROM tblretailer t where t.DIST_CODE = i_old_dist_code and (upper(t.ACCESS_TO) = 'SALES' or upper(t.ACCESS_TO) = 'BOTH');
--SELECT count(*) into v_ret_count FROM tblretailer t where t.DIST_CODE = i_old_dist_code and upper(t.ACCESS_TO) = 'SALES' and upper(t.stage) in ('APPROVED','INACTIVE');
IF v_ret_count=i_ret_list.count THEN
IF i_territory_remapping = 1 THEN
result := 'no_ret_left';
v_flag := 'false';
END IF;
ELSE
IF i_territory_remapping != 1 THEN
result := 'ret_left';
v_flag := 'false';
END IF;
END IF;
END IF;
IF i_ret_list is null or i_ret_list.count = 0 THEN
result := 'empty retailers list';
v_flag := 'false';
END IF;
/*FOR i IN i_ret_list.FIRST .. i_ret_list.LAST
LOOP
IF v_ret_codes is null
THEN
v_ret_codes := ''''||i_ret_list(i)||'''';
ELSE
v_ret_codes := v_ret_codes||','''||i_ret_list(i)||'''';
END IF;
IF v_ret_codes is null
THEN
v_ret_codes := i_ret_list(i);
ELSE
v_ret_codes := v_ret_codes||','||i_ret_list(i);
END IF;
END LOOP;
i_ret_codes := v_ret_codes;
v_flag := 'false';
result := 'success';*/
IF v_flag = 'true' THEN
FOR i IN i_ret_list.FIRST .. i_ret_list.LAST
LOOP
IF v_ret_codes is null
THEN
v_ret_codes := ''''||i_ret_list(i)||'''';
ELSE
v_ret_codes := v_ret_codes||','''||i_ret_list(i)||'''';
END IF;
END LOOP;
--i_ret_codes := v_ret_codes;
--update tblretailer set dist_code=i_new_dist_code,DIST_ID=to_number(i_new_dist_code),cluster_code=(select cluster_code from tblemployee where empcode = i_new_dist_code),FOSID='',FOS_CODE='',DSR_ID='',DSR_CODE='',LAST_UPDATED_DATE=sysdate where retcode in (v_ret_codes);
v_query := 'update tblretailer set dist_code='||i_new_dist_code||',DIST_ID=to_number('||i_new_dist_code||'),cluster_code=(select cluster_code from tblemployee where empcode = '||i_new_dist_code||'),FOSID='''',FOS_CODE='''',DSR_ID='''',DSR_CODE='''',LAST_UPDATED_DATE=sysdate where retcode in ('||v_ret_codes||')';
execute immediate (v_query);
--i_query :='update tblretailer set dist_code='||i_new_dist_code||',DIST_ID=to_number('||i_new_dist_code||'),cluster_code=(select cluster_code from tblemployee where empcode = '||i_new_dist_code||'),FOSID='',FOS_CODE='',DSR_ID='',DSR_CODE='',LAST_UPDATED_DATE=sysdate where retcode in ('||v_ret_codes||');';
insert into TBL_TRANSFER_SUP_MASTER(MASTER_ID,TRANS_ID,TRANS_DONEBY_ROLENAME,TRANS_DONEBY_ID,TRANS_FROM_ROLENAME,TRANS_FROM,TRANS_TO_ROLENAME,TRANS_TO,ACTIVITY_CODE,TRANS_DATE,TRANSFER_REASON,LAST_UPDATED_DATE)
values(SUP_MASTER_TRANS_ID_SEQ.nextval,SUP_MASTER_TRANS_ID_SEQ.nextval,i_trans_doneby_rolename,i_trans_doneby_id,i_trans_dist_rolename,i_old_dist_code,i_trans_dist_rolename,i_new_dist_code,'101',sysdate,i_remapping_reason,sysdate) return TRANS_ID into v_trans_id;
FOR i IN i_ret_list.FIRST .. i_ret_list.LAST
LOOP
insert into TBL_TRANSFER_SUP_DTLS(DTLS_ID,TRANS_ID,TRANS_ON_ROLENAME,TRANS_ON_ID,LAST_UPDATED_DATE)
values(SUP_DTLS_ID_SEQ.nextval,v_trans_id,i_trans_ret_rolename,i_ret_list(i),sysdate);
END LOOP;
IF SQL%ROWCOUNT>0 THEN
result := 'success';
ELSE
result := 'failure';
END IF;
--update tblstock set NEW_DIST_CODE_REMAP=i_new_dist_code,REMAP_DATE=sysdate,LAST_UPDATED_DATE=sysdate where (DIST_CODE=i_old_dist_code or NEW_DIST_CODE_REMAP=i_old_dist_code) and RET_CODE in (v_ret_codes);
v_query := 'update tblstock set NEW_DIST_CODE_REMAP='||i_new_dist_code||',REMAP_DATE=sysdate,LAST_UPDATED_DATE=sysdate where (DIST_CODE='||i_old_dist_code||' or NEW_DIST_CODE_REMAP='||i_old_dist_code||') and RET_CODE in ('||v_ret_codes||')';
execute immediate (v_query);
i_o_query := v_query;
insert all into TBL_ACTIVITY_LOG (LOG_ID,TRANS_ID,ACTIVITY_DONEBY_ROLENAME,ACTIVITY_DONEBY_ID,ACTIVITY_REFERENCE_ID,ACTIVITY_CODE,ACTIVITY_DATE)
values(ACTIVITY_LOG_TRANS_ID_SEQ.NEXTVAL,ACTIVITY_LOG_TRANS_ID_SEQ.NEXTVAL,i_trans_doneby_rolename,i_trans_doneby_id,v_trans_id,
act_code,sysdate) select log_config.ACTIVITY_CODE act_code from TBL_ACTIVITY_LOG_CONFIG log_config
where upper(log_config.ACTIVITY_TYPE)= upper(i_activity_type);
END IF;
END;
/
Java Code :-
try{
if(ret_list.size()>0)
ret_code = ret_list.toArray();
con = ConnectionManager.getDirectConnection();
ArrayDescriptor descriptor = ArrayDescriptor.createDescriptor(PropertyLoader.RET_SECONDARY_V_ARRAY,con);
ARRAY array_to_pass = new ARRAY( descriptor,con, ret_code );
cstmt = con.prepareCall("{ call SP_DIST_RETAILER_REMAP(?,?,?,?,?,?,?,?,?,?,?,?)}");
cstmt.setString(1,old_dist_code.trim());
cstmt.setString(2,new_dist_code.trim());
if(territory_remapping)
cstmt.setInt(3,1);
else
cstmt.setInt(3,2);
cstmt.setString(4,remapping_reason);
cstmt.setString(5,userVO.getRolename().trim());
cstmt.setInt(6,userVO.getEmpid());
cstmt.setString(7,PropertyLoader.DISTRIBUOTR_ROLENAME);
cstmt.setString(8,PropertyLoader.RETAILER_ROLENAME);
cstmt.setString(9,PropertyLoader.ACTIVITY_TYPES_RETAILER_REMAPPING);
cstmt.setArray(10,array_to_pass);
cstmt.registerOutParameter(11,Types.VARCHAR);
cstmt.registerOutParameter(12,Types.VARCHAR);
/*cstmt.registerOutParameter(13,Types.VARCHAR);*/
cstmt.execute();
status = cstmt.getString(11);
System.out.println("Remap Update Query "+cstmt.getString(12));
//System.out.println(cstmt.getString(13));
}
If the value stored in PropertyLoader.RET_SECONDARY_V_ARRAY is not "V_ARRAY", then you are using different types; even if they are declared identically (e.g. both are table of number) this will not work.
You're hitting this data type compatibility restriction:
You can assign a collection to a collection variable only if they have
the same data type. Having the same element type is not enough.
You're trying to call the procedure with a parameter that is a different type to the one it's expecting, which is what the error message is telling you.
The procedure which you are using is should be properly declared in the place which you are using it. For an example if it is under a user and in a package then it should be in that order. The username, package and procedurename.
I need to check the parameters in the stored procedure if it is entered then I need to select that
i=j=k=l=m=1;
IF (p_plant_cd IS NULL) THEN
i=0;
END IF;
IF(p_global_duns_nbr IS NULL) THEN
j=0
END IF;
IF(p_global_duns_nbr IS NULL) THEN
k=0
END IF;
IF(p_matrl_grp IS NULL) THEN
l=0
END IF;
IF (p_mrp IS NULL) THEN
m=0
END IF ;
Which ever value is 1 I need to add corresponding parameters in the variable v_select
For eg ;
if k and l are 1 then
v_select='p_global_duns_nbr,p_matrl_grp'
Pls suggest me how to do this.
You can declare a variable , holding column names , then concat to select statement and you have SQL select statement in v_select , use it as you want
declare
v_columns varchar2(255);
v_select varchar2(2000);
v_result sys_refcursor;
begin
v_columns := 'rownum';
IF p_plant_cd = 1 THEN
v_columns := v_columns || ',p_plant_cd';
END IF;
IF p_global_duns_nbr = 1 THEN
v_columns := v_columns || ',p_global_duns_nbr';
END IF;
IF p_global_duns_nbr = 1 THEN
v_columns := v_columns || ',p_global_duns_nbr';
END IF;
IF p_matrl_grp = 1 THEN
v_columns := v_columns || ',p_matrl_grp';
END IF;
IF p_mrp = 1 THEN
v_columns := v_columns || ',p_mrp';
END IF;
v_select := 'SELECT ' || v_columns || ' FROM table';
open v_result for v_select;
end;
Is it possible to run a for each loop on a PL/SQL array?
for i in my_array.first ..my_array.last loop
--do_something with my_array(i);
end loop;
It's no possible to iterate over the associative arrays with a non numeric index with a FOR-loop. The solution below works just fine.
-- for-each key in (associative-array) loop ...
declare
type items_type is table of varchar2(32) index by varchar2(32);
items items_type;
begin
items('10') := 'item 10';
items('20') := 'item 20';
items('30') := 'item 30';
dbms_output.put_line('items=' || items.count);
<<for_each>> declare key varchar2(32); begin loop
key := case when key is null then items.first else items.next(key) end;
exit when key is null;
dbms_output.put_line('item(' || key || ')=' || items(key));
--do something with an item
end loop; end for_each;
end;
In my opinion 0xdb solution is best.
Even if you have numeric index it is better to us this construct
DECLARE
TYPE TTab_SomeTable IS TABLE OF VARCHAR2(2000) INDEX BY PLS_INTEGER;
--
vt_SomeTable TTab_SomeTable;
vi_Idx NUMBER;
BEGIN
vt_SomeTable(1) := 'First';
vt_SomeTable(2) := 'Second';
vt_SomeTable(5) := 'Fifth';
vt_SomeTable(10) := 'Tenth';
vi_Idx := vt_SomeTable.FIRST;
LOOP
--
EXIT WHEN vi_Idx IS NULL;
--
dbms_output.Put_Line('vt_SomeTable(' || vi_Idx || ') = ' || vt_SomeTable(vi_Idx));
--
vi_Idx := vt_SomeTable.NEXT(vi_Idx);
--
END LOOP vi_Idx;
END;
It is not susceptible to index discontinuity like below two examples, which will fail on index 3:
DECLARE
TYPE TTab_SomeTable IS TABLE OF VARCHAR2(2000) INDEX BY PLS_INTEGER;
--
vt_SomeTable TTab_SomeTable;
BEGIN
vt_SomeTable(1) := 'First';
vt_SomeTable(2) := 'Second';
vt_SomeTable(5) := 'Fifth';
vt_SomeTable(10) := 'Tenth';
-- Throw No_data_found on vi_Idx = 3
FOR vi_Idx IN vt_SomeTable.FIRST .. vt_SomeTable.LAST
LOOP
dbms_output.Put_Line('vt_SomeTable(' || vi_Idx || ') = ' || vt_SomeTable(vi_Idx));
END LOOP vi_Idx;
END;
DECLARE
TYPE TTab_SomeTable IS TABLE OF VARCHAR2(2000) INDEX BY PLS_INTEGER;
--
vt_SomeTable TTab_SomeTable;
BEGIN
vt_SomeTable(1) := 'First';
vt_SomeTable(2) := 'Second';
vt_SomeTable(5) := 'Fifth';
vt_SomeTable(10) := 'Tenth';
-- Throw No_data_found on vi_Idx = 3.
FOR vi_Idx IN 1 .. vt_SomeTable.COUNT
LOOP
dbms_output.Put_Line('vt_SomeTable(' || vi_Idx || ') = ' || vt_SomeTable(vi_Idx));
END LOOP vi_Idx;
END;