Assigning values to a table record - collections

I tried the below code and wanted to see output of the assigned record
but it gives nothing.
CREATE OR REPLACE TYPE t_obj as object(
book_name varchar2(20),
ISBN number,
author varchar2(20)
);
CREATE OR REPLACE TYPE t_table as table of t_obj;
CREATE OR REPLACE FUNCTION fun_ret_tab
RETURN t_table
IS
vl_table t_table := t_table ();
BEGIN
FOR j IN 1 .. vl_table.COUNT
LOOP
vl_table.EXTEND;
vl_table (vl_table.LAST) :=
t_obj ('oracle programming', 2132, 'steven feurestein');
END LOOP;
return vl_table;
END;

As vl_table.COUNT is 0, try the following:
create or replace FUNCTION fun_ret_tab
RETURN t_table
IS
vl_table t_table := t_table ();
BEGIN
-- Start Loop at 0
FOR j IN 0 .. vl_table.COUNT
LOOP
vl_table.EXTEND;
vl_table (vl_table.LAST) :=
t_obj ('oracle programming', 2132, 'steven feurestein');
END LOOP;
return vl_table;
END;

Related

How to select from a table using DBMS_SQL

I'm trying to use dbms_sql package to select from a table but I can't do it.. can anyone please tell me what I am doing wrong?
create or replace function dbsm_sql_SELECT(age IN NUMBER) return VARCHAR2 is
q VARCHAR2(500);
ret NUMBER;
c1 number;
begin
q := 'SELECT users_name FROM USERS_TABLE WHERE USERS_AGE = :1';
c1 := dbms_sql.open_cursor;
dbms_sql.parse(c1,q,dbms_sql.native);
dbms_sql.bind_variable(c => c1, name => ':1' , value => age );
ret := dbms_sql.execute(c1);
dbms_sql.close_cursor(c1);
dbms_output.put_line(ret);
return('a');
end dbsm_sql_SELECT;
here.. try this.. I've switched to querying from a common table
clear screen
SET serveroutput ON size 1000000
declare
function dbsm_sql_SELECT(age IN NUMBER) return VARCHAR2 is
q VARCHAR2(500);
ret NUMBER;
c1 number;
l_username VARCHAR2(40);
begin
q := 'SELECT username FROM user_USERS WHERE user_id < :1';
c1 := dbms_sql.open_cursor;
dbms_sql.parse(c1,q,dbms_sql.native);
DBMS_SQL.DEFINE_COLUMN(c1, 1, l_username,40);
--define any other columns you want
dbms_sql.bind_variable(c => c1, name => ':1' , value => age );
ret := dbms_sql.execute(c1);
LOOP
IF DBMS_SQL.FETCH_ROWS(c1)>0 THEN
DBMS_SQL.COLUMN_VALUE(c1, 1, l_username);
--get values of any columns you previously defined
ELSE
-- No more rows to copy:
EXIT;
END IF;
end loop;
dbms_sql.close_cursor(c1);
dbms_output.put_line(ret);
--return teh correct value
return(l_username);
end ;
begin
dbms_output.put_line(dbsm_sql_SELECT(1000));
end;
/

i have a function which returns multiple o/p i need to call this function to insert in a table

create or replace type branch_warehouse as object (wh_id number,wh_name varchar2(100));
create or replace type id_warehouse_list as table of branch_warehouse;
function get_ware_house_branch(p_BRANCH_IDS in out varchar2)
return id_warehouse_list is
l_warehouse_list id_warehouse_list := id_warehouse_list();
str varchar2(300);
begin
str := 'SELECT BRANCH_WAREHOUSE(w.wh_id, w.wh_name)
FROM POD_WAREHOUSE_MASTER W
where ( W.BRANCH_ID IN (' || p_BRANCH_IDS || '))';
execute immediate str bulk collect into l_warehouse_list;
for i in l_warehouse_list.first..l_warehouse_list.last loop
dbms_output.put_line(l_warehouse_list(i).wh_id || ', ' || l_warehouse_list(i).wh_name);
end loop;
return l_warehouse_list;
end;
procedure insert_place_warehouse_map(p_PLACE_NAME in varchar2,
p_BRANCH_IDS in number,
p_status out varchar2,
p_status_dtl out varchar2) is
v_ID number;
l_warehouse_list id_warehouse_list := id_warehouse_list();
begin
v_ID := get_place_id (p_PLACE_NAME);
l_warehouse_list := get_ware_house_branch(p_BRANCH_IDS);
for i in l_warehouse_list.first..l_warehouse_list.last loop
insert into pod_place_warehouse_map(
id,
place_id,
wh_id,
wh_name)
values(
pod_unique_val_seq.nextval,
v_ID,
l_warehouse_list(i).wh_id,
l_warehouse_list(i).wh_name);
v_rec_cnt := sql%rowcount;
end loop;
commit;
p_status := 'SUCESS';
p_status_dtl := v_rec_cnt||' Record Inserted Successfully';
exception
when others then
rollback;
p_status_dtl := sqlcode||' - '||substr(sqlerrm,1,100);
p_status := 'ERROR';
end;
i am getting error p_BRANCH_IDS cannot be used as assignment operator in the 2nd code
first code is working,
please help
This is because the parameter is declared as in out in first code, but as in in second.

while executing the function when I'm providing i/p [parameter which is not in table I'm getting error; otherwise it gets executed]

create or replace function get_ware_house_master(p_WAREHOUSE_IDS in varchar2)
return id_wh_id
is
l_warehouse_list id_wh.id := id_wh_id();
str varchar2(300);
begin
str := 'SELECT BM(w.wh_id)
FROM pod_place_warehouse_mapping_tb W
where ( W.wh_id IN (' ||p_WAREHOUSE_IDS || '))';
execute immediate str bulk collect into l_warehouse_list;
for i in l_warehouse_list.first..l_warehouse_list.last loop
dbms_output.put_line(l_warehouse_list(i).wh_id);
end loop;
return l_warehouse_list;
end get_ware_house_master;
How to handle the data which are not present in the table I need to use if l_warehouse_list = null then dbms_output('No DATA FOUND') but if data is not present in the table mentioned in the function I get below error:
numeric or value change error
You could use the count() function on that collection of yours:
create or replace function get_ware_house_master(p_WAREHOUSE_IDS in varchar2)
return id_wh_id
is
l_warehouse_list id_wh.id := id_wh_id();
str varchar2(300);
begin
str := 'SELECT BM(w.wh_id)
FROM pod_place_warehouse_mapping_tb W
where ( W.wh_id IN (' ||p_WAREHOUSE_IDS || '))';
execute immediate str bulk collect into l_warehouse_list;
if l_warehouse_list.count() >0 then
for i in l_warehouse_list.first..l_warehouse_list.last loop
dbms_output.put_line(l_warehouse_list(i).wh_id);
end loop;
else
dbms_output.put_line('No data');
end if;
return l_warehouse_list;
end get_ware_house_master;
Here is how to illustrate the latest with little simplification to your code:
CREATE OR REPLACE TYPE id_wh_id AS TABLE OF VARCHAR2(100);
create or replace function get_ware_house_master(p_WAREHOUSE_IDS in varchar2)
return id_wh_id
is
l_warehouse_list id_wh_id := id_wh_id();
str varchar2(300);
begin
str := 'SELECT * from dual where ''a''=''' ||p_WAREHOUSE_IDS || '''';
dbms_output.put_line(str);
execute immediate str bulk collect into l_warehouse_list;
if l_warehouse_list.count() >0 then
for i in l_warehouse_list.first..l_warehouse_list.last loop
dbms_output.put_line(l_warehouse_list(i));
end loop;
else
dbms_output.put_line('No data');
end if;
return l_warehouse_list;
end get_ware_house_master;
/
-- and call to the function:
select get_ware_house_master('sbi') from dual
union all select get_ware_house_master('a') from dual
;

Dynamic String contcatination in Cursor

I have a function which concatinates the value for a cursor. Its now only concatinates 4 columns and that column name should be hardcoded. Is there a way to have a generic solution for this, such that if i pass a cursor it will automatically concatinate data regardless of column name and number of columns in 11g.
FUNCTION generateData(p_dataCursor IN SYS_REFCURSOR)
RETURN VARCHAR2 AS
-- ---------------------------------------------------------------------
crlf VARCHAR2(2) := chr(13)||chr(10);
lv_message VARCHAR2(32000);
BEGIN
FOR rec IN p_dataCursor
LOOP
lv_message := lv_message || rec.a||','||rec.b||','||rec.c||','||rec.d || crlf;
END LOOP;
RETURN lv_message;
END;
Since 11g Oracle built-in package DBMS_SQL provides function TO_CURSOR_NUMBER - "This function takes an OPENed strongly or weakly-typed ref cursor and transforms it into a DBMS_SQL cursor number."
Example code:
DECLARE
l_cursor SYS_REFCURSOR;
FUNCTION generateData(p_dataCursor IN SYS_REFCURSOR)
RETURN VARCHAR2 AS
curs SYS_REFCURSOR := p_dataCursor;
l_cursorid NUMBER;
l_column_count INTEGER;
l_describe_table DBMS_SQL.DESC_TAB;
l_numvar NUMBER;
l_ignore INTEGER;
l_value VARCHAR2(2000);
l_coma VARCHAR2(10);
crlf VARCHAR2(2) := chr(13)||chr(10);
lv_message VARCHAR2(32000);
BEGIN
l_cursorid := dbms_sql.to_cursor_number( curs );
dbms_sql.describe_columns( l_cursorid, l_column_count, l_describe_table );
FOR i IN 1..l_column_count LOOP
dbms_sql.define_column(l_cursorid, i, l_value, 2000);
END LOOP;
LOOP
IF DBMS_SQL.FETCH_ROWS(l_cursorid)>0 THEN
l_coma := '';
FOR i IN 1..l_column_count LOOP
dbms_sql.column_value(l_cursorid, i, l_value);
lv_message := lv_message || l_coma || l_value;
l_coma := ',';
END LOOP;
lv_message := lv_message || crlf;
ELSE
EXIT;
END IF;
END LOOP;
dbms_sql.close_cursor( l_cursorid );
RETURN lv_message;
END;
BEGIN
open l_cursor FOR 'SELECT 1 as A, 2 AS B, 3 AS C, 4 AS D FROM DUAL UNION ALL SELECT 1 as A, 2 AS B, 3 AS C, 4 AS D FROM DUAL';
dbms_Output.put_Line(generateData(l_cursor));
END;
/

Function returns a table

Here I have a function which takes 'COMMA SEPARATED STRING' and returns a pipelined table.
create or replace
FUNCTION parse_comma_delimited
(
iv_list IN VARCHAR2,
v_delimiter IN VARCHAR2 DEFAULT ','
)
RETURN parse_comma_delimited_pkg.tt_v_tablevalues_type PIPELINED
AS
v_list VARCHAR2(8000) := iv_list;
v_item VARCHAR2(255);
v_temp SYS_REFCURSOR;
v_temp_1 TT_V_TABLEVALUES%ROWTYPE;
BEGIN
WHILE ( LENGTHB(v_list) > 0 )
LOOP
BEGIN
IF INSTR(v_list, v_delimiter) > 0 THEN
BEGIN
v_item := SUBSTR(v_list, 1, (INSTR(v_list, v_delimiter) - 1)) ;
v_list := SUBSTR(v_list, (INSTR(v_list, v_delimiter)
|| LENGTHB(v_delimiter)), LENGTHB(v_list)) ;
END;
ELSE
BEGIN
v_item := v_list ;
v_list := NULL ;
END;
END IF;
INSERT INTO tt_v_tablevalues ( item ) VALUES (v_item);
END;
END LOOP;
OPEN v_temp FOR
SELECT *
FROM tt_v_tablevalues;
LOOP
FETCH v_temp INTO v_temp_1;
EXIT WHEN v_temp%NOTFOUND;
PIPE ROW ( v_temp_1 );
END LOOP;
END;
But when I call the function its retuning only one row.
INSERT INTO SRC_PK_INSERT (pk_key)
SELECT *
FROM TABLE(parse_comma_delimited((
SELECT *
FROM SRC_PK_INSERT
WHERE RULE_NAME = 'RULES'
)));
With a pipelined function you populate the row_type, then call pipe row.
See the documentation here: http://docs.oracle.com/cd/B28359_01/appdev.111/b28425/pipe_paral_tbl.htm#CHDJEGHC
Example from docs:
CREATE FUNCTION StockPivot(p refcur_pkg.refcur_t) RETURN TickerTypeSet
PIPELINED IS
out_rec TickerType := TickerType(NULL,NULL,NULL);
in_rec p%ROWTYPE;
BEGIN
LOOP
FETCH p INTO in_rec;
EXIT WHEN p%NOTFOUND;
-- first row
out_rec.ticker := in_rec.Ticker;
out_rec.PriceType := 'O';
out_rec.price := in_rec.OpenPrice;
PIPE ROW(out_rec);
-- second row
out_rec.PriceType := 'C';
out_rec.Price := in_rec.ClosePrice;
PIPE ROW(out_rec);
END LOOP;
CLOSE p;
RETURN;
END;
/

Resources