How to select from a table using DBMS_SQL - plsql

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

Related

plsql select return value using dbms_sql 12c

Well in Oracle, EXECUTE IMMEDIATE is simpler than resorting to the dbms_sql package with the exception of cross tenant queries as dbms_sql as of 12c allows a container argument.
However, in a small test, I'm getting nothing. i.e.,
set serveroutput on
declare
ret pls_integer;
cnt pls_integer := 0;
cols number := 0;
ctx varchar2(128) := NULL;
cur number;
stmt varchar2(100);
begin
stmt := 'select count(*) from scott.emp';
cur := dbms_sql.open_cursor;
dbms_sql.parse(c => cur,
statement => stmt,
language_flag => dbms_sql.native,
container => ctx);
dbms_sql.define_column(cur, 1, cnt);
ret := dbms_sql.execute(cur);
dbms_output.put_line('execute = '||ret);
ret := dbms_sql.fetch_rows(cur);
dbms_output.put_line(' fetch = '||ret);
dbms_output.put_line(stmt||' = '||cnt);
dbms_sql.close_cursor(cur);
end;
/
The container when null - meaning current or ignored would allow the query to sent to the target container. I however suspect I'm missing something trivial, hence my question; thanks in advance. Sample output:
SQL> show con_name
CON_NAME
------------------------------
PDB1
SQL> set echo on
SQL> #f
SQL> set serveroutput on
SQL> declare
2 ret pls_integer;
3 cnt pls_integer := 0;
4 cols number := 0;
5 ctx varchar2(128) := NULL;
6 cur number;
7 stmt varchar2(100);
8 begin
9 stmt := 'select count(*) from scott.emp';
10 cur := dbms_sql.open_cursor;
11 dbms_sql.parse(c => cur,
12 statement => stmt,
13 language_flag => dbms_sql.native,
14 container => ctx);
15 dbms_sql.define_column(cur, 1, cnt);
16 ret := dbms_sql.execute(cur);
17 dbms_output.put_line('execute = '||ret);
18 ret := dbms_sql.fetch_rows(cur);
19 dbms_output.put_line('fetch = '||ret);
20 dbms_output.put_line(stmt||' = '||cnt);
21 dbms_sql.close_cursor(cur);
22 end;
23 /
execute = 0
fetch = 1
select count(*) from scott.emp = 0
PL/SQL procedure successfully completed.
You need to get the actual column value from the result set with:
dbms_sql.column_value(cur, 1, cnt);
From the documentation:
COLUMN_VALUE Procedure
This procedure returns the value of the cursor element for a given position in a given cursor. This procedure is used to access the data fetched by calling FETCH_ROWS.
So your code would be:
set serveroutput on
declare
ret pls_integer;
cnt pls_integer := 0;
cols number := 0;
ctx varchar2(128) := NULL;
cur number;
stmt varchar2(100);
begin
stmt := 'select count(*) from scott.emp';
cur := dbms_sql.open_cursor;
dbms_sql.parse(c => cur,
statement => stmt,
language_flag => dbms_sql.native,
container => ctx);
dbms_sql.define_column(cur, 1, cnt);
ret := dbms_sql.execute(cur);
dbms_output.put_line('execute = '||ret);
ret := dbms_sql.fetch_rows(cur);
dbms_output.put_line(' fetch = '||ret);
-- get the actual value from the column into its variable
dbms_sql.column_value(cur, 1, cnt);
dbms_output.put_line(stmt||' = '||cnt);
dbms_sql.close_cursor(cur);
end;
/
If I do that (admittedly in 11g, so without the container argument - which doesn't seem to really be relevant to your actual issue) and against the hr.employees table instead, I see:
execute = 0
fetch = 1
select count(*) from employees = 107
PL/SQL procedure successfully completed.
SQL> select count(*) from employees;
COUNT(*)
----------
107

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.

SYS.DBMS_DDL.WRAP not allowing pragma and intctx

I am using the below procedure to wrap the PL/SQL Code.
declare
l_source DBMS_SQL.VARCHAR2A;
l_wrap DBMS_SQL.VARCHAR2A;
l_wrap1 clob;
typ_ibt utl_file.file_type;
cnt number := 0;
v_directory varchar2(400) := 'd:\ftpedi\eqpm\eqpm_hold\';
cursor cur_name_get is
select distinct name object_name,type object_type
from user_source
where type = 'PROCEDURE'
and name = 'PROCESS_TIME_INSERT';
cursor cut_text_get ( p_type in varchar2 , p_name in varchar2 ) is
select replace(text,chr(10),'') text
from user_source
where type = p_type
and name = p_name;
begin
for i in cur_name_get
loop
l_source.delete;l_wrap.delete;
open cut_text_get ( i.object_type,i.object_name );
fetch cut_text_get bulk collect into l_source;
close cut_text_get;
l_source (1) := 'CREATE OR REPLACE ' || l_source (1);
l_wrap := SYS.DBMS_DDL.WRAP(ddl => l_source,
lb => 1,
ub => l_source.count);
for i in 1..l_wrap.count
loop
if i = 1
then
l_wrap1 := l_wrap(i);
else
l_wrap1 := l_wrap1 || l_wrap(i);
end if;
insert into ibt_global_inter_transfer ( git_process_id,git_c_1)
values ( 3004, l_wrap1 );
end loop;
end loop;
exception when others
then
dbms_output.put_line('sqlerrm '||sqlerrm||dbms_utility.format_error_backtrace);
end;
The above procedures warps the normal procedure, but not allowing the special character like 'PRAGMA'.
The below is the sample procedure, which is not wrapping.
CREATE OR REPLACE
PROCEDURE xml_insert ( p_in_xml in xmltype ,p_status out varchar2,p_message out varchar2) is
intctx DBMS_XMLSTORE.ctxtype;
rows number;
begin
p_status := 'S';
p_message := 'Success';
intctx := Dbms_xmlstore.newcontext('IBT_GLOBAL_INTER_TRANSFER');
dbms_xmlstore.clearupdatecolumnlist(intctx);
dbms_xmlstore.setupdatecolumn(intCtx,'GIT_PROCESS_ID');
dbms_xmlstore.setupdatecolumn(intCtx,'GIT_SESSION_ID');
rows := Dbms_xmlstore.insertxml(intctx,p_in_xml);
dbms_xmlstore.closecontext(intctx);
exception when others
then
p_status := 'R';
p_message := sqlerrm||dbms_utility.format_error_backtrace;
return;
end;
Could anyone help?
Update
(I misunderstood the problem. I thought you meant the wrapped code wasn't created, now I understand the real problem is that the wrapped output does not compile.)
Remove the replace, there needs to be white space between some of the lines.
Replace:
--select replace(text,chr(10),'') text
with:
select text
Procedure:
CREATE OR REPLACE
PROCEDURE xml_insert ( p_in_xml in xmltype ,p_status out varchar2,p_message out varchar2) is
intctx DBMS_XMLSTORE.ctxtype;
rows number;
pragma autonomous_transaction; --ADDED
begin
p_status := 'S';
p_message := 'Success';
intctx := Dbms_xmlstore.newcontext('IBT_GLOBAL_INTER_TRANSFER');
dbms_xmlstore.clearupdatecolumnlist(intctx);
dbms_xmlstore.setupdatecolumn(intCtx,'GIT_PROCESS_ID');
dbms_xmlstore.setupdatecolumn(intCtx,'GIT_SESSION_ID');
rows := Dbms_xmlstore.insertxml(intctx,p_in_xml);
dbms_xmlstore.closecontext(intctx);
exception when others
then
p_status := 'R';
p_message := sqlerrm||dbms_utility.format_error_backtrace;
return;
end;
/
PL/SQL Block wrapping code:
declare
l_source DBMS_SQL.VARCHAR2A;
l_wrap DBMS_SQL.VARCHAR2A;
l_wrap1 clob;
typ_ibt utl_file.file_type;
cnt number := 0;
v_directory varchar2(400) := 'd:\ftpedi\eqpm\eqpm_hold\';
cursor cur_name_get is
select distinct name object_name,type object_type
from user_source
where type = 'PROCEDURE'
and name = 'XML_INSERT'; --CHANGED
cursor cut_text_get ( p_type in varchar2 , p_name in varchar2 ) is
--select replace(text,chr(10),'') text --WOOPS!
select text
from user_source
where type = p_type
and name = p_name;
begin
for i in cur_name_get
loop
l_source.delete;l_wrap.delete;
open cut_text_get ( i.object_type,i.object_name );
fetch cut_text_get bulk collect into l_source;
close cut_text_get;
l_source (1) := 'CREATE OR REPLACE ' || l_source (1);
l_wrap := SYS.DBMS_DDL.WRAP(ddl => l_source,
lb => 1,
ub => l_source.count);
for i in 1..l_wrap.count
loop
if i = 1
then
l_wrap1 := l_wrap(i);
else
l_wrap1 := l_wrap1 || l_wrap(i);
end if;
--insert into ibt_global_inter_transfer ( git_process_id,git_c_1)
--values ( 3004, l_wrap1 );
dbms_output.put_line(l_wrap1);
end loop;
end loop;
exception when others
then
dbms_output.put_line('sqlerrm '||sqlerrm||dbms_utility.format_error_backtrace);
end;
/

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