bind variable error in stored procedure - oracle

Here is my procedure code :
create or replace Procedure SP_CUSTOMER_PRODUCT_QRY
( PARENT_PARTYID IN varchar2,PRODUCT_ID IN varchar2,PRODUCT_STATUS IN varchar2,PAGING IN varchar2,OFFSET IN varchar2,LIST_OF_PARTIES OUT VARCHAR2 )
AS
V_SQL_WHERE varchar2(10000):= null;
V_SQL varchar2(10000):='SELECT PARTYID FROM TABLE1';
V_check varchar2(10000) := '' ;
BEGIN
IF(PARENT_PARTYID IS NOT NULL) THEN
V_SQL_WHERE := V_SQL_WHERE || ' PARENT_PARTYID=:1';
END IF;
IF(PRODUCT_ID IS NOT NULL) THEN
IF (V_SQL_WHERE is not null) THEN
V_SQL_WHERE := V_SQL_WHERE || ' AND ';
END IF;
V_SQL_WHERE := V_SQL_WHERE || ' PRODUCT_ID=:2';
END IF;
IF(PRODUCT_STATUS IS NOT NULL) THEN
IF (V_SQL_WHERE is not null) THEN
V_SQL_WHERE := V_SQL_WHERE || ' AND ';
END IF;
V_SQL_WHERE := V_SQL_WHERE || ' PRODUCT_STATUS=:3';
END IF;
IF (V_SQL_WHERE is not null) then
V_SQL := V_SQL || ' WHERE ' || V_SQL_WHERE;
end if;
dbms_output.put_line(V_SQL);
EXECUTE IMMEDIATE V_SQL INTO LIST_OF_PARTIES;
EXCEPTION
WHEN NO_DATA_FOUND THEN
V_check:= '' ;
END;
I have used bind variables ,unable to understand the issue.Is it mandatory to bind all parameters even if they are not used in procedure
When I am passing any input I am getting error as
java.sql.SQLException: ORA-01008: not all variables bound

In this case there is no need for using dynamic plsql. Try to do this this way:
CREATE OR REPLACE PROCEDURE SP_CUSTOMER_PRODUCT_QRY
( P_PARENT_PARTYID IN VARCHAR2,
P_PRODUCT_ID IN VARCHAR2,
P_PRODUCT_STATUS IN VARCHAR2,
P_PAGING IN VARCHAR2,
P_OFFSET IN VARCHAR2,
P_LIST_OF_PARTIES OUT VARCHAR2 )
AS
CURSOR CUR_PARTYID
IS
SELECT PARTYID
FROM TABLE1
WHERE (P_PARENT_PARTYID IS NULL
OR PARENT_PARTYID = P_PARENT_PARTYID)
AND (P_PRODUCT_ID IS NULL
OR PRODUCT_ID = P_PRODUCT_ID)
AND (P_PRODUCT_STATUS IS NULL
OR PRODUCT_STATUS = P_PRODUCT_STATUS);
BEGIN
OPEN CUR_PARTYID;
FETCH CUR_PARTYID INTO P_LIST_OF_PARTIES;
CLOSE CUR_PARTYID;
END;
/

You need the "using" clause with your execute immediate for the 3 variables in the where clause.
for example:
EXECUTE IMMEDIATE 'DELETE FROM dept WHERE deptno = :num' USING dept_id;

Related

Can we use collection variable as a table in execute immediate select statement? [duplicate]

I am building a function on PL/SQL using Oracle 11g.
I am trying to use a table variable within an EXECUTE IMMEDIATE statement, but it is not working, as you can see:
ERROR at line 1:
ORA-00904: "CENTER_OBJECTS": invalid identifier
ORA-06512: at "HIGIIA.KNN_JOIN", line 18
The code I am using is...
First, the type definitions
CREATE TYPE join_t IS OBJECT (
inn char(40),
out char(40)
);
/
CREATE TYPE join_jt IS TABLE OF join_t;
/
CREATE TYPE blob_t IS OBJECT (
id CHAR(40),
fv BLOB
);
/
CREATE TYPE blob_tt IS TABLE OF blob_t;
/
The function is:
create or replace FUNCTION knn_join (tab_inn IN varchar2, tab_out IN varchar2, blob_col1 IN varchar2, blob_col2 IN varchar2, dist_alg in VARCHAR2, kv in NUMBER ) RETURN join_jt
IS
var_fv BLOB;
var_id CHAR(40);
center_objects blob_tt := blob_tt();
retval join_jt := join_jt ();
join_table join_jt := join_jt();
sql_stmt1 varchar2(400);
sql_stmt2 varchar2(400);
BEGIN
sql_stmt1 := 'SELECT blob_t(ROWIDTOCHAR(rowid),' || blob_col1 || ') FROM ' || tab_out;
sql_stmt2 := 'SELECT join_t(ROWIDTOCHAR(r.rowid), center_objects(idx).id) FROM ' || tab_inn || ' r WHERE ' || dist_alg || '_knn(r.' || blob_col2 || ', center_objects(idx).' || blob_col1 || ')<=' || kv;
dbms_output.put_line(sql_stmt2);
EXECUTE IMMEDIATE sql_stmt1 BULK COLLECT INTO center_objects;
for idx in center_objects.first()..center_objects.last()
loop
--SELECT join_t(ROWIDTOCHAR(r.rowid), center_objects(idx).id) BULK COLLECT INTO join_table FROM londonfv r WHERE manhattan_knn(r.fv, center_objects(idx).fv) <=5;
EXECUTE IMMEDIATE sql_stmt2 BULK COLLECT INTO join_table;
for idx2 in join_table.first()..join_table.last()
loop
retval.extend();
retval(retval.count()) := join_table(idx2);
end loop;
end loop;
RETURN retval;
END;
/
To run the function:
select * from TABLE(knn_join('london','cophirfv','fv','fv','manhattan',5));
I am trying to use run the statement 'SELECT join_t(ROWIDTOCHAR(r.rowid), center_objects(idx).id) BULK COLLECT INTO join_table FROM london r WHERE manhattan_knn(r.fv, center_objects(idx).fv) <=5' using the EXECUTE IMMEDIATE, but it does not work because I am using a variable in it.
Can someone give me a hand on it?
Thanks in advance!
You can't refer to a local PL/SQL variable inside a dynamic SQL statement, because it is out of scope within the SQL context used by the dynamic call. You could replace your first call:
SELECT join_t(ROWIDTOCHAR(r.rowid), center_objects(idx).id) FROM ' ...
with a bind variable:
SELECT join_t(ROWIDTOCHAR(r.rowid), :id FROM ' ...
EXECUTE IMMEDIATE ... USING center_objects(idx).id ...
but you can't do what when the object attribute is variable too:
... ', center_objects(idx).' || blob_col1 || ')<='...
although - at least in the example you've shown - the only object attribute name available is fv, regardless of the table column names passed in to the function - so that could be hard-coded; and thus a bind variable could be used:
... ', :fv)<='...
EXECUTE IMMEDIATE ... USING center_objects(idx).id, center_objects(idx).fv ...
and the kv value should also be a bind variable, so you'd end up with:
create or replace FUNCTION knn_join (tab_inn IN varchar2, tab_out IN varchar2,
blob_col1 IN varchar2, blob_col2 IN varchar2, dist_alg in VARCHAR2, kv in NUMBER )
RETURN join_jt
IS
center_objects blob_tt := blob_tt();
retval join_jt := join_jt ();
join_table join_jt := join_jt();
sql_stmt1 varchar2(400);
sql_stmt2 varchar2(400);
BEGIN
sql_stmt1 := 'SELECT blob_t(ROWIDTOCHAR(rowid),' || blob_col1 || ') FROM ' || tab_out;
sql_stmt2 := 'SELECT join_t(ROWIDTOCHAR(r.rowid), :id) FROM ' || tab_inn || ' r WHERE '
|| dist_alg || '_knn(r.' || blob_col2 || ', :fv)<= :kv';
dbms_output.put_line(sql_stmt1);
dbms_output.put_line(sql_stmt2);
EXECUTE IMMEDIATE sql_stmt1 BULK COLLECT INTO center_objects;
for idx in center_objects.first()..center_objects.last()
loop
EXECUTE IMMEDIATE sql_stmt2 BULK COLLECT INTO join_table
USING center_objects(idx).id, center_objects(idx).fv, kv;
for idx2 in join_table.first()..join_table.last()
loop
retval.extend();
retval(retval.count()) := join_table(idx2);
end loop;
end loop;
RETURN retval;
END;
/
As far as I can tell you could still do the join within the dynamic SQL statement, and eliminate the loops and the need for the intermediate center_objects and join_table collections:
create or replace FUNCTION knn_join (tab_inn IN varchar2, tab_out IN varchar2,
blob_col1 IN varchar2, blob_col2 IN varchar2, dist_alg in VARCHAR2, kv in NUMBER )
RETURN join_jt
IS
retval join_jt;
sql_stmt varchar2(400);
BEGIN
sql_stmt := 'SELECT join_t(ROWIDTOCHAR(tinn.rowid), ROWIDTOCHAR(tout.rowid))'
|| ' FROM ' || tab_inn || ' tinn JOIN ' || tab_out || ' tout'
|| ' ON ' || dist_alg || '_knn(tinn.fv, tout.fv) <= :kv';
dbms_output.put_line(sql_stmt);
EXECUTE IMMEDIATE sql_stmt BULK COLLECT INTO retval USING kv;
RETURN retval;
END;
/
When you call it as you've shown:
select * from TABLE(knn_join('london','cophirfv','fv','fv','manhattan',5));
that's the equivalent of the hard-coded:
SELECT join_t(ROWIDTOCHAR(tinn.rowid), ROWIDTOCHAR(tout.rowid))
FROM london tinn
JOIN cophirfv tout
ON manhattan_knn(tinn.fv, tout.fv) <= 5
... so I guess you can verify whether that hard-coded version gives you the results you expect first. (Adding sample data and expected results to the question would have helped, of course).
That join condition may be expensive, depending on what the function is doing, how may rows are in each table (as every row in each table has to be compared with every row in the other), whether you actually have other filters, etc. The loop version would be even worse though. Without more information there isn't much to be done about that anyway.
As an aside, using varchar2 instead of char for the object attributes would be more normal; that's also the data type returned by the rowidtochar() function.

PLS 00302 : component DATA_TYPE must de declared in function

I have to following oracle function, build_select, which create a select request. The return value is in the following format:
select col1 ||'|'||col2 ||'|'||col3 from table;
Below is the build_select function:
create or replace FUNCTION build_select (
p_table_name IN VARCHAR2
)
RETURN VARCHAR2
AS
l_ret VARCHAR2 (32767);
BEGIN
FOR eachcol IN ( SELECT column_name, data_type
, LEAD (column_name), LEAD (data_type)
OVER (
PARTITION BY table_name ORDER BY column_id
)
next_column
FROM all_tab_cols
WHERE table_name = p_table_name
ORDER BY column_id)
LOOP
IF eachcol.data_type = 'CLOB' THEN
l_ret := l_ret || dbms_lob.substr( eachcol.column_name, 3000, 1 ) || CASE WHEN eachcol.next_column IS NULL THEN NULL ELSE ' ||''|''||' END;
ELSE
l_ret := l_ret || eachcol.column_name || CASE WHEN eachcol.next_column IS NULL THEN NULL ELSE ' ||''|''||' END;
END IF;
END LOOP;
IF l_ret IS NULL
THEN
raise_application_error (-20001, 'table ' || p_table_name || ' not found');
END IF;
l_ret := 'select ' || l_ret || ' from ' || p_table_name || ';';
RETURN l_ret;
END build_select;
What I want to do is to test if the data type of the column is CLOB and if so then return it as
dbms_lob.substr( eachcol.column_name, 3000, 1 )
I have added the if else condition in the loop part. But I am getting the error :
PLS 00302 : component DATA_TYPE must de declared.
Any help pls?
I need to do so cause when I am doing a spool of the returned select, it is not returning all the columns cause of the CLOB data type.
I think your function should be this:
create or replace FUNCTION build_select (
p_table_name IN VARCHAR2
)
RETURN VARCHAR2
AS
l_ret VARCHAR2 (32767);
BEGIN
FOR eachcol IN ( SELECT column_name, data_type
FROM all_tab_cols
WHERE table_name = p_table_name
ORDER BY column_id)
LOOP
IF eachcol.data_type = 'CLOB' THEN
l_ret := l_ret || 'dbms_lob.substr( '||eachcol.column_name||', 3000, 1 ),';
ELSE
l_ret := l_ret || eachcol.column_name||',';
END IF;
END LOOP;
IF l_ret IS NULL
THEN
raise_application_error (-20001, 'table ' || p_table_name || ' not found');
END IF;
l_ret := 'select ' || regexp_replace(l_ret, ',$', NULL) || ' from ' || p_table_name || ';';
RETURN l_ret;
END build_select;
Note, ALL_TAB_COLS selects also system-generated hidden columns and invisible columns which could be a problem. Query ALL_TAB_COLUMNS if you like to filter them.

How can I use bind variable in plsql function

I have a function like this:
create or replace function params
(
p_pr varchar2,
p_qu_id varchar2,
p_date date := sysdate,
p_param varchar2 := null
)
return varchar2
as
...
sql_stmt varchar2(4000);
rc sys_refcursor;
...
BEGIN
sql_stmt := 'select parameter_name, parameter_value from ' || p_pr | '.v_view where query_id = ''' || p_qu_id || '''';
IF p_param IS NOT NULL
THEN
sql_stmt := sql_stmt || ' and parameter_value=''' || p_param || '''';
END IF;
OPEN rc FOR sql_stmt;
LOOP
FETCH rc
INTO v_param_name, v_param_value;
EXIT WHEN rc%NOTFOUND;
EXIT WHEN v_param_value is NULL;
....
DBA said this function using hard parse, I must use bind variable in this function. How can I do that?
Thanks.
I must use bind variable in this function.
The solution is to use a placeholder in the template SQL ...
sql_stmt := sql_stmt || ' and parameter_value= :p1';
... then pass the actual value with the USING clause when you open the ref cursor.
Things are slightly tricky because you are executing different statements depending on whether the parameter is populated. So you need to do something like this instead:
sql_stmt := 'select parameter_name, parameter_value from ' || p_pr
|| '.v_view where query_id =:p1';
IF p_param IS NOT NULL
THEN
sql_stmt := sql_stmt || ' and parameter_value= :p2';
OPEN rc FOR sql_stmt using p_qu_id, p_param;
else
OPEN rc FOR sql_stmt using p_qu_id;
END IF;
LOOP
Note that p_pr - a schema name - cannot be replaced with a bind variable.

Converting a dynamic query to use bind variables in Oracle 11g

I have a dynamic search query that I would like to convert to make use of bind variables. The dynamic portion of the of query is in the where clause, and using a series of if statements to build a string that is concatenated to the rest of the query string. That query is then used in the for clause of a openstatement, which the result set is the return parameter. I'm not really sure how to accomplish this.
Here is the stored procedure:
PROCEDURE run_search(i_unit_id IN lu_unit.fsu_id%TYPE,
i_equipment IN tbl_component.component%TYPE,
i_equipment_status IN tbl_component.equipment_status%TYPE,
i_equipment_type IN tbl_component.equipment_type%TYPE,
i_equipment_subtype IN tbl_component.equipment_sub_type%TYPE,
i_system_id IN tbl_component.system_id%TYPE,
i_association_code IN tbl_component_assc_code.assc_code%TYPE,
i_manufacturer IN lu_component_manu_model.equipment_manufacturer%TYPE,
i_manumodel IN lu_component_manu_model.equipment_model%TYPE,
o_results OUT sys_refcursor) AS
v_query VARCHAR2(32767) := '';
v_where VARCHAR2(32767) := ' 1= 1';
BEGIN
IF i_unit_id IS NOT NULL THEN
v_where := v_where || ' AND unit_id=''' || i_unit_id ||''' ';
END IF;
IF i_equipment IS NOT NULL THEN
v_where := v_where || ' AND lower(component) LIKE ''%' || lower(i_equipment) ||'%'' ';
END IF;
IF i_equipment_status IS NOT NULL THEN
v_where := v_where || ' AND equipment_status=''' || i_equipment_status ||''' ';
END IF;
IF i_equipment_type IS NOT NULL THEN
v_where := v_where || ' AND equipment_type=''' || i_equipment_type ||''' ';
END IF;
IF i_equipment_subtype IS NOT NULL THEN
v_where := v_where || ' AND equipment_sub_type=''' || i_equipment_subtype ||''' ';
END IF;
IF i_system_id IS NOT NULL THEN
v_where := v_where || ' AND system_id=''' || i_system_id || ''' ';
END IF;
IF i_association_code IS NOT NULL THEN
v_where := v_where || ' AND EXISTS ( select null from tbl_component_assc_code where assc_code = ''' || i_association_code || ''' and component_id = vcs.component_id )';
END IF;
IF i_manufacturer IS NOT NULL THEN
v_where := v_where || ' AND equipment_manufacturer=''' || i_manufacturer || ''' ';
END IF;
IF i_manuModel IS NOT NULL THEN
v_where := v_where || ' AND equipment_model=''' || i_manuModel || ''' ';
END IF;
v_query :=
' SELECT rownum, results.* '
||' FROM '
||' ( SELECT '
||' count(*) OVER () ' || ' as total_results, '
||''
||' site_id, site_display_name, '
||' unit_id, unit_display_name, '
||' system_id, system_display_name, '
||' component_id, component, component_description, equipment_description, '
||' equipment_status, equipment_model, equipment_serial_number, equipment_type, equipment_sub_type, '
||' template_ids '
||''
||' FROM vw_component_search '
||' WHERE ' || v_where
||' ORDER BY unit_display_name, component '
||' ) results '
;
OPEN o_results FOR v_query;
END run_search;
You can write the query without dynamically creating it so you include all the parameters and just ignore those which are NULL (please profile it to test whether there are any performance issues compared to a dynamic query):
PROCEDURE run_search(i_unit_id IN lu_unit.fsu_id%TYPE,
i_equipment IN tbl_component.component%TYPE,
i_equipment_status IN tbl_component.equipment_status%TYPE,
i_equipment_type IN tbl_component.equipment_type%TYPE,
i_equipment_subtype IN tbl_component.equipment_sub_type%TYPE,
i_system_id IN tbl_component.system_id%TYPE,
i_association_code IN tbl_component_assc_code.assc_code%TYPE,
i_manufacturer IN lu_component_manu_model.equipment_manufacturer%TYPE,
i_manumodel IN lu_component_manu_model.equipment_model%TYPE,
o_results OUT sys_refcursor)
AS
BEGIN
OPEN o_results FOR
SELECT rownum,
results.*
FROM ( SELECT count(*) OVER () as total_results,
site_id,
site_display_name,
unit_id,
unit_display_name,
system_id,
system_display_name,
component_id,
component,
component_description,
equipment_description,
equipment_status,
equipment_model,
equipment_serial_number,
equipment_type,
equipment_sub_type,
template_ids
FROM vw_component_search
WHERE ( i_unit_id IS NULL
OR unit_id= i_unit_id )
AND ( i_equipment IS NULL
OR lower(component) LIKE '%' || lower(i_equipment) || '%' )
AND ( i_equipment_status IS NULL
OR equipment_status= i_equipment_status )
AND ( i_equipment_type IS NULL
OR equipment_type= i_equipment_type )
AND ( i_equipment_subtype IS NULL
OR equipment_sub_type= i_equipment_subtype )
AND ( i_system_id IS NULL
OR system_id= i_system_id )
AND ( i_association_code IS NULL
OR EXISTS ( select null
from tbl_component_assc_code
where assc_code = i_association_code
and component_id = vcs.component_id ) )
AND ( i_manufacturer IS NULL
OR equipment_manufacturer= i_manufacturer )
AND ( i_manuModel IS NULL
OR equipment_model= i_manuModel )
ORDER BY unit_display_name, component
) results;
END run_search;
(I've not compiled the above code - so there may be some errors).
The best way is to avoid such headache at all. 'SP returning resultset' is a usual practise in a poor legacy things such as MSSQL2000, but in unnecessary and doubtful in Oracle.
If you wish to do this, I'd advice you to do something like this:
procedure MakeGarbage(value_mask varchar2) return sys_refcursor is
cur integer;
stmt varchar2(32000 byte);
type TParamTable is table of varchar2(1000) index by varchar2(20);
params TParamTable;
i varchar2(20);
begin
stmt := 'select * from table where 1 = 1 ';
if value_mask is not null then
stmt := stmt || ' and value like :value_mask ';
params('value_mask') := value_mask;
end if;
...
cur := dbms_sql.create_cursor;
dbms_sql.open_cursor(cur, stmt, dbms_sql.native);
i := params.first;
while i is not null loop
dbms_sql.bind_variable(i, params(i));
i := params.next(i);
end loop;
return dbms_sql.to_ref_cursor(cur);
end;
every reference to a PL/SQL variable is in fact a bind variable.
you can check this asktom link
https://asktom.oracle.com/pls/asktom/f?p=100:11:0::::P11_QUESTION_ID:2320123769177
and check "Dynamic SQL" from this link http://www.akadia.com/services/ora_bind_variables.html

Concatenation of CLOB datatypes in a LOOP in PL/SQL

I am trying to concatenate clobs in a PL/SQL loop and it has been returning null whilst when using DBMS_OUTPUT prints out the loop values and when executing each result of the clobs gives an output as well.
The system is meant to execute an already stored SQL in a table based on the report name passed into it. This particular report has many report names; hence the concatenation of each of the reports. The arguments passed are the report name, version of the report you're interested in, the kind of separator you want, and an argument list for the unknowns in the SQL if any. There are also two main types of SQL; 1 that needs the table_name be replaced with a temp table_name and another that needs an ID be appended to a table_name in the SQL.
please find below the code for the REPREF1 function.
CREATE OR REPLACE FUNCTION REPREF1(P_VER IN VARCHAR2 DEFAULT 'LATEST',
P_SEPARATOR IN VARCHAR2 DEFAULT ', ',
P_ARGLIST IN VAR DEFAULT NULL) RETURN CLOB IS
L_CLOB CLOB;
FUNCTION GET_CLOB(P_REPNAM IN VARCHAR2,
P_VER IN VARCHAR2 DEFAULT 'LATEST',
P_SEPARATOR IN VARCHAR2 DEFAULT ', ',
P_ARGLIST IN VAR DEFAULT NULL) RETURN CLOB IS
---------------------------------------------------------------------------------
-- TITLE - GET_CLOB beta - b.0 DATE 2010Mar12
--
-- DESCRIPTION - A function that return a report based on the report name put in
--
-- USAGE - select get_clob(p_repnam,p_ver, p_separator, var(varay(val_1,...val_n), varay(val_1,...val_n))) FROM dual
-----------------------------------------------------------------------------------------------------------------------------
V_SQL VARCHAR2(32767);
L_RESULT CLOB;
V_TITLE VARCHAR2(4000);
V_REPDATE VARCHAR2(30);
V_CNT NUMBER(2);
V_NUMARG NUMBER(3);
V_CDCRU NUMBER(3);
V_BCNT NUMBER(3);
V_NEWTABDAT VARCHAR2(30);
V_NEWTABLIN VARCHAR2(30);
L_COLLIST VARAY;
V_VER VARCHAR2(6);
N PLS_INTEGER;
V_CNTTAB NUMBER(3);
-- EXEC_SQL_CLOB
FUNCTION EXEC_SQL_CLOB(P_SQL IN VARCHAR2,
P_NUMARG IN NUMBER,
P_COLLIST IN VARAY DEFAULT NULL,
P_ARGLIST IN VARAY DEFAULT NULL,
P_SEPARATOR IN VARCHAR2 DEFAULT '') RETURN CLOB IS
------------------------------------------------------------------------------------------------------
-- TITLE - EXEC_SQL_CLOB beta - b.0 DATE 2010Mar22
--
-- DESCRIPTION - A function that returns a clob value after executing the sql query that is passed into it
--
-- USAGE - select exec_sql_clob(p_sql, p_numarg, var(varay(val_1, val_2,...val_n), varay(val_1, val_2,...val_n))) FROM dual
---------------------------------------------------------------------------------------------------------------
L_CUR INTEGER DEFAULT DBMS_SQL.OPEN_CURSOR;
L_STATUS INTEGER;
V_COL VARCHAR2(4000);
L_RESULT CLOB;
L_COLCNT NUMBER DEFAULT 0;
L_SEPARATOR VARCHAR2(10) DEFAULT '';
V_NUMARG NUMBER(3);
BEGIN
-- parse the query for the report
DBMS_SQL.PARSE(L_CUR, P_SQL, DBMS_SQL.NATIVE);
-- whilst it is not more than 255 per line
FOR I IN 1 .. 255
LOOP
BEGIN
-- define each column in the select list
DBMS_SQL.DEFINE_COLUMN(L_CUR, I, V_COL, 2000);
L_COLCNT := I;
EXCEPTION
WHEN OTHERS THEN
IF (SQLCODE = -1007) THEN
EXIT;
ELSE
RAISE;
END IF;
END;
END LOOP;
-- If query has no bind variables
IF (P_ARGLIST IS NULL) THEN
IF (P_NUMARG = 0) THEN
-- Execute the query in the cursor
L_STATUS := DBMS_SQL.EXECUTE(L_CUR);
LOOP
-- Exit loop when fetch is complete
EXIT WHEN(DBMS_SQL.FETCH_ROWS(L_CUR) <= 0);
L_SEPARATOR := '';
FOR I IN 1 .. L_COLCNT
LOOP
DBMS_SQL.COLUMN_VALUE(L_CUR, I, V_COL);
L_RESULT := L_RESULT || L_SEPARATOR || V_COL;
L_RESULT := REPLACE(REPLACE(L_RESULT, CHR(13) || CHR(10), ' '), CHR(10), ' ');
L_SEPARATOR := P_SEPARATOR;
END LOOP;
L_RESULT := L_RESULT || CHR(13);
END LOOP;
ELSE
RAISE_APPLICATION_ERROR(-20011, ' INCORRECT NUMBER OF ARGUMENTS PASSED IN LIST ');
END IF;
-- Query has bind variables
ELSE
-- Check if the numarg passed is the same has stored in the table
SELECT NUMARG
INTO V_NUMARG
FROM REPVER
WHERE REPCODE = P_SQL;
-- If number of arguments is greater than 0
IF (V_NUMARG > 0) THEN
-- Check if the number of arguments are the same
IF (P_NUMARG = V_NUMARG) THEN
-- Replace the bind variables in the query
FOR J IN 1 .. P_ARGLIST.COUNT
LOOP
DBMS_SQL.BIND_VARIABLE(L_CUR, P_COLLIST(J), P_ARGLIST(J));
END LOOP;
-- Execute the query in the cursor
L_STATUS := DBMS_SQL.EXECUTE(L_CUR);
LOOP
-- Exit loop when fetch is complete
EXIT WHEN(DBMS_SQL.FETCH_ROWS(L_CUR) <= 0);
L_SEPARATOR := '';
FOR I IN 1 .. L_COLCNT
LOOP
DBMS_SQL.COLUMN_VALUE(L_CUR, I, V_COL);
L_RESULT := L_RESULT || L_SEPARATOR || V_COL;
L_RESULT := REPLACE(REPLACE(L_RESULT, CHR(13) || CHR(10), ' '), CHR(10), ' ');
L_SEPARATOR := P_SEPARATOR;
END LOOP;
L_RESULT := L_RESULT || CHR(13);
END LOOP;
ELSE
RAISE_APPLICATION_ERROR(-20011, ' INCORRECT NUMBER OF ARGUMENTS PASSED IN LIST ');
END IF;
ELSE
-- If the number of argument is equal to 0
IF (P_NUMARG = 0) THEN
-- Execute the query in the cursor
L_STATUS := DBMS_SQL.EXECUTE(L_CUR);
LOOP
-- Exit loop when fetch is complete
EXIT WHEN(DBMS_SQL.FETCH_ROWS(L_CUR) <= 0);
L_SEPARATOR := '';
FOR I IN 1 .. L_COLCNT
LOOP
DBMS_SQL.COLUMN_VALUE(L_CUR, I, V_COL);
L_RESULT := L_RESULT || L_SEPARATOR || V_COL;
L_RESULT := REPLACE(REPLACE(L_RESULT, CHR(13) || CHR(10), ' '), CHR(10), ' ');
L_SEPARATOR := P_SEPARATOR;
END LOOP;
L_RESULT := L_RESULT || CHR(13);
END LOOP;
ELSE
RAISE_APPLICATION_ERROR(-20011, ' INCORRECT NUMBER OF ARGUMENTS PASSED IN LIST ');
END IF;
END IF;
END IF;
-- Close cursor
DBMS_SQL.CLOSE_CURSOR(L_CUR);
RETURN L_RESULT;
END EXEC_SQL_CLOB;
BEGIN
-- Check if the version entered is null or latest
IF (P_VER IS NULL)
OR (UPPER(P_VER) = UPPER('LATEST')) THEN
SELECT MAX(VER)
INTO V_VER
FROM REPORT B, REPVER R
WHERE UPPER(REPNAM) = UPPER(P_REPNAM)
AND B.REPREF = R.REPREF;
ELSE
V_VER := P_VER;
END IF;
-- Check if the repname and version entered exists
SELECT COUNT(*)
INTO V_CNT
FROM REPORT B, REPVER R
WHERE UPPER(REPNAM) = UPPER(P_REPNAM)
AND VER = V_VER
AND B.REPREF = R.REPREF;
IF (V_CNT > 0) THEN
-- Store the SQL statement, title and number of arguments of the report name passed.
SELECT REPCODE, REPTITLE, NUMARG, COLLIST
INTO V_SQL, V_TITLE, V_NUMARG, L_COLLIST
FROM REPVER R, REPORT B
WHERE UPPER(REPNAM) = UPPER(P_REPNAM)
AND B.REPREF = R.REPREF
AND VER = V_VER;
V_REPDATE := TO_CHAR(SYSDATE, 'YYYY-MM-DD HH24:MI');
L_RESULT := V_TITLE || ' (' || P_REPNAM || ' version ' || V_VER || ') generated ' || V_REPDATE || CHR(13) || CHR(13);
-- Check for some specific type of queries
SELECT COUNT(*)
INTO V_CDCRU
FROM REPVER R, REPORT B
WHERE CTDDATA = 'Y'
AND UPPER(REPNAM) = UPPER(P_REPNAM)
AND B.REPREF = R.REPREF
AND VER = V_VER;
SELECT COUNT(*)
INTO V_BCNT
FROM REPVER R, BODCREPS B
WHERE BENLIST = 'Y'
AND UPPER(REPNAM) = UPPER(P_REPNAM)
AND B.REPREF = R.REPREF
AND VER = V_VER;
IF (V_CDCRU > 0) THEN
V_NEWTABDATA := 'CT_' || 'DAT_' || P_ARGLIST(1) (P_ARGLIST(1).FIRST);
V_NEWTABLINK := 'CT_' || 'LIN_' || P_ARGLIST(1) (P_ARGLIST(1).FIRST);
-- Check if the tables exist
SELECT COUNT(*)
INTO V_CNTTAB
FROM ALL_TABLES
WHERE TABLE_NAME = V_NEWTABDAT
OR TABLE_NAME = V_NEWTABLIN
AND OWNER = 'SCOTT';
IF (V_CNTTAB > 0) THEN
V_SQL := UPPER(V_SQL);
V_SQL := REPLACE(V_SQL, 'CT_DAT_CRU', V_NEWTABDAT);
V_SQL := REPLACE(V_SQL, 'CT_LIN_CRU', V_NEWTABLIN);
ELSE
V_SQL := 'SELECT ''THE TABLE NOT CREATED YET''
FROM DUAL';
END IF;
END IF;
IF (V_BCNT > 0) THEN
V_SQL := UPPER(V_SQL);
V_SQL := REPLACE(V_SQL, 'LIST', P_ARGLIST(1) (P_ARGLIST(1).LAST));
END IF;
IF (P_ARGLIST IS NULL) THEN
-- execute the query
L_RESULT := L_RESULT || EXEC_SQL_CLOB(V_SQL, V_NUMARG, L_COLLIST, NULL, P_SEPARATOR);
ELSE
N := P_ARGLIST.COUNT;
-- execute the query
L_RESULT := L_RESULT || EXEC_SQL_CLOB(V_SQL, V_NUMARG, L_COLLIST, P_ARGLIST(N), P_SEPARATOR);
END IF;
RETURN L_RESULT;
ELSE
RAISE_APPLICATION_ERROR(-20012, P_REPNAM || ' or ' || P_VER || ' DOES NOT EXIST ');
END IF;
END GET_CLOB;
BEGIN
FOR I IN (SELECT REPNAM
FROM REPORT
WHERE REPREF NOT IN ('R01', 'R02', 'R03', 'R04'))
LOOP
SELECT CONCAT_CLOB(GET_CLOB(I.REPNAM, P_VER, P_SEPARATOR, P_ARGLIST))
INTO L_CLOB
FROM DUAL;
DBMS_OUTPUT.PUT_LINE(I.REPNAM);
-- DBMS_OUTPUT.PUT_LINE (COUNT(i.REPNAM));
END LOOP;
RETURN L_CLOB;
END REPREF1;
/
Cheers,
Tunde
Many thanks APC for making the code look better.
#Robert, the last loop in the code returns null even with the CONCAT_CLOB aggregate function that concatenates clobs.
FOR I IN (SELECT REPNAM
FROM REPORT
WHERE REPREF NOT IN ('R01', 'R02', 'R03', 'R04'))
LOOP
SELECT CONCAT_CLOB(GET_CLOB(I.REPNAM, P_VER, P_SEPARATOR, P_ARGLIST))
INTO L_CLOB
FROM DUAL;
DBMS_OUTPUT.PUT_LINE(I.REPNAM);
END LOOP;
when I try this,
FOR I IN (SELECT REPNAM
FROM REPORT
WHERE REPREF NOT IN ('R01', 'R02', 'R03', 'R04'))
LOOP
L_CLOB := L_CLOB || CHR(13) || GET_CLOB(I.REPNAM, P_VER, P_SEPARATOR, P_ARGLIST);
DBMS_OUTPUT.PUT_LINE(I.REPNAM);
END LOOP;
It also gives null; but this time the dbms output for the repnam are not complete.
Don't know about your code. Here is how it works for me:
Whenever I create a function returning a clob value I do this:
function foo return clob is
l_clob clob;
begin
dbms_lob.createtemporary(lob_loc => l_clob, cache => true, dur => dbms_lob.call);
...
return l_clob;
end;
When concatenating values into a clob I use a function:
procedure add_string_to_clob(p_lob in out nocopy clob
,p_string varchar2) is
begin
dbms_lob.writeappend(lob_loc => p_lob, amount => length(p_string), buffer => p_string);
end;
You have to use
dbms_lob.substr(your clob parameter,start position, length)
e.g
dbms_output('my clob value:' || dbms_lob.substr(your clob parameter,start position, length);
But you can print in a string max 4000 character, you can then use this in a looping function to print 4000 characters in each line.

Resources