IF statement contains SELECT statment - oracle

When running this:
create or replace FUNCTION GET_FUNCTION(STATUS_ID IN VARCHAR2)
RETURN VARCHAR2
IS STATUS_NAME VARCHAR2(255);
BEGIN
IF NVL(STATUS_ID) THEN
STATUS_NAME:='';
ELSIF STATUS_ID LIKE '0' THEN
STATUS_NAME:='UNASSIGNED'
ELSE
SELECT TABLE_A.NAME INTO STATUS_NAME FROM TABLE_A where
TABLE_A.ID=STATUS_ID;
END IF;
RETURN(STATUS_NAME);
end;
I get the following error:
Error(9,4): PLS-00103: Encountered the symbol "ELSE" when expecting one of the following:
* & = - + ; < / > at in is mod remainder not rem <an exponent (**)> <> or != or ~= >= <= <> and or like like2 like4 likec between || multiset member submultiset
The symbol ";" was substituted for "ELSE" to continue.
What is the problem?

CREATE OR REPLACE FUNCTION GET_FUNCTION(STATUS_ID IN VARCHAR2)
RETURN VARCHAR2
IS STATUS_NAME VARCHAR2(255);
BEGIN
IF NVL(STATUS_ID) THEN
STATUS_NAME := '';
ELSIF STATUS_ID = '0' THEN
STATUS_NAME := 'UNASSIGNED';
ELSE
SELECT TABLE_A.NAME INTO STATUS_NAME
FROM TABLE_A
WHERE TABLE_A.ID = STATUS_ID;
END IF;
RETURN STATUS_NAME;
END;

I think that is one is a little bit beter
CREATE OR REPLACE FUNCTION GET_FUNCTION(STATUS_ID IN VARCHAR2)
RETURN VARCHAR2
IS
cursor c_tab (B_STATUS_ID IN TABLE_A.ID%TYPE)
is
SELECT TABLE_A.NAME
FROM TABLE_A
WHERE TABLE_A.ID = B_STATUS_ID;
STATUS_NAME VARCHAR2(255);
BEGIN
IF NVL(STATUS_ID, -1) = -1 THEN
-- IF STATUS_ID IS NULL THEN ==> This one is also possible!
STATUS_NAME := '';
ELSIF STATUS_ID = '0' THEN
STATUS_NAME := 'UNASSIGNED';
ELSE
OPEN C_TAB (STATUS_ID);
FETCH C_TAB INTO STATUS_NAME;
CLOSE C_TAB;
END IF;
RETURN STATUS_NAME;
END;

You need to add semicolon after each statement to execute (line 8 in your code - I've added a comment):
create or replace FUNCTION GET_FUNCTION(STATUS_ID IN VARCHAR2)
RETURN VARCHAR2
IS STATUS_NAME VARCHAR2(255);
BEGIN
IF NVL(STATUS_ID) THEN
STATUS_NAME:='';
ELSIF STATUS_ID LIKE '0' THEN
STATUS_NAME:='UNASSIGNED'; /* HERE HAS TO BE A SEMICOLON TOO */
ELSE
SELECT TABLE_A.NAME INTO STATUS_NAME FROM TABLE_A where
TABLE_A.ID=STATUS_ID;
END IF;
RETURN(STATUS_NAME);
end;

Related

How can I do a procedure that tells me the size of the substrings?

I am learning plsql and I have some doubts.
How do I get the size of all substrings in the string? The way I did it, I'm only managing to return the size of just the first substring.
set serveroutput on;
create or replace procedure pr_size (value varchar2)
as
answer varchar2 (300): = '';
begin
for x in 1 .. length (value) loop
cont: = x;
if substr (value, x, 1) = ''
then dbms_output.put_line ('Size:' || length (answer));
exit;
else answer: = answer || substr (value, x, 1);
end if;
end loop;
end;
call pr_size ('Word size calculation test');
you can do something like this
DECLARE
type string_table is table of VARCHAR2(100);
st string_table;
BEGIN
SELECT regexp_substr('THIS IS TEST', '[^ ]+', 1, LEVEL) BULK COLLECT INTO st FROM dual CONNECT by level <= regexp_count('THIS IS TEST', '[^ ]+');
for i in 1..st.COUNT
LOOP
dbms_output.put_line(length(st(i)));
END LOOP;
END;
If you want a string of length like in your code then
CREATE OR REPLACE PROCEDURE pr_size (value varchar2)
AS
type string_table is table of VARCHAR2(100);
st string_table;
answer VARCHAR2(100);
BEGIN
SELECT regexp_substr(value, '[^ ]+', 1, LEVEL) BULK COLLECT INTO st FROM dual CONNECT by level <= regexp_count(value, '[^ ]+');
for i in 1..st.COUNT
LOOP
answer := length(st(i))||' '||answer;
END LOOP;
dbms_output.put_line(answer);
END;
If you want to use your logic then I have corrected your logic
DECLARE
value VARCHAR2(100) := 'this is test for word length';
answer VARCHAR2(100);
cont PLS_INTEGER := 0;
BEGIN
for x in 1 .. length (value) loop
if substr (value, x, 1) = ' ' then
dbms_output.put_line ('Size:' || cont);
cont := 0;
ELSE
cont := cont + 1;
end if;
end loop;
dbms_output.put_line ('Size:' || cont);
END;

Oracle APEX 20.1 Charts Error with “PL/SQL Function Body returning SQL Query”

I have a problem with new charts in Oracle APEX 20.1.
I need to do chart from PL/SQL Function Body returning SQL Query,
but it only works if I do it with some exact parameters. All variables return from the same submitted page.
If I use all variables as parameter then i get error: ORA-20999: PL/SQL function body did not return a value.
If I use variable :P2_OBJECT and parameter for :P2_YEAR and :P2_ANNUAL_TIME then i get error: ORA-20999: PL/SQL function body did not return a value.
If I use variable :P2_YEAR and parameter for :P2_OBJECT and :P2_ANNUAL_TIME then i get error: ORA-20999: Parsing returned query results in "ORA-20999: Failed to parse SQL query! ORA-06550: line 2, column 402: ORA-00936: missing expression".
If I use variable :P2_ANNUAL_TIME and parameter for :P2_OBJECT and :P2_YEAR then i get error: ORA-20999: Parsing returned query results in "ORA-20999: Failed to parse SQL query! ORA-06550: line 2, column 113: ORA-01741: illegal zero-length identifier".
but in a classic report the same function with variables works just fine...
this source for chart works:
declare l_sql varchar2(2000) ;
begin
select F_CHARTS(4020 , 2018 ,'TIM_MM',
:P2_LEVELS, :P2_SUB_LEVELS, :P2_SQL_CONDITION, :P2_WAREHOUSE, :P2_UNIT_OF_MEASURE)
into l_sql from dual;
return l_sql ;
end ;
but this does not:
declare
l_sql varchar2(2000) ;
begin
select F_CHARTS(:P2_OBJECT,:P2_YEAR,:P2_ANNUAL_TIME,
:P2_LEVELS, :P2_SUB_LEVELS, :P2_SQL_CONDITION, :P2_WAREHOUSE, :P2_UNIT_OF_MEASURE)
into l_sql from dual;
return l_sql ;
end ;
This is the function:
create or replace FUNCTION F_CHARTS(
cod in NUMBER,
year in NUMBER,
t_time in varchar2,
v_dims in varchar2,
p_subl in varchar2,
cod_filter in NUMBER,
w_warehouse in varchar2,
amount in NUMBER)
return varchar2 is s varchar2(4000);
g2 boolean := false;
l NUMBER := 0;
m VARCHAR2(1000) :='';
c VARCHAR2(40) :='';
w VARCHAR2(40) :='';
sql_cond VARCHAR2(4000) :='';
ope VARCHAR2(5) :='';
OGG_FACT_TAB VARCHAR2(40);
OGG_COL_GROUP VARCHAR2(40);
OGG_COL_SUBGR VARCHAR2(40);
OGG_COL_SUM VARCHAR2(200);
OGG_COL_TIME VARCHAR2(40);
OGG_ALIAS_SUM VARCHAR2(100);
OGG_DIMS_TAB VARCHAR2(40);
OGG_COL_KEY VARCHAR2(40);
OGG_COL_DES VARCHAR2(40);
OGG_ALIAS_TAB VARCHAR2(100);
OGG_AVERAGES VARCHAR2(1);
OGG_CLASS NUMBER;
OGG_COL_SUM2 VARCHAR2(200);
cursor times is SELECT QTM_DESCRIPTION,QTM_DES_VALUE,QTM_VALUE FROM Q_TIME WHERE QTM_FIELD_NAME=t_time ORDER BY QTM_SEQUENCE;
BEGIN
select OGG_CLASS,OGG_FACT_TAB,OGG_COL_GROUP,OGG_COL_SUM,OGG_COL_TIME,OGG_ALIAS_SUM,OGG_DIMS_TAB,OGG_COL_KEY,OGG_COL_DES,OGG_ALIAS_TAB,OGG_COL_SUBGR,TRIM(OGG_AVERAGE),TRIM(OGG_COL_SUM2) into OGG_CLASS,OGG_FACT_TAB,OGG_COL_GROUP,OGG_COL_SUM,OGG_COL_TIME,OGG_ALIAS_SUM,OGG_DIMS_TAB,OGG_COL_KEY,OGG_COL_DES,OGG_ALIAS_TAB,OGG_COL_SUBGR,OGG_AVERAGES,OGG_COL_SUM2 from Q_OBJECT where OGG_CODE = cod;
IF ( p_subl is not null and p_subl <> 'null' and TRIM(p_subl) is not null and p_subl <> to_char(cod)
and OGG_COL_SUBGR IS not NULL and TRIM(OGG_COL_SUBGR) is not null ) THEN
g2:=true;
IF ( OGG_CLASS = 1 AND amount = 1 AND OGG_COL_SUM2 IS NOT NULL ) THEN
OGG_COL_SUBGR:='''kg''';
OGG_COL_SUM:=OGG_COL_SUM2;
ELSE
OGG_COL_SUBGR:='f.'||OGG_COL_SUBGR;
END IF;
END IF;
IF (OGG_AVERAGES is not null and OGG_AVERAGES='S') THEN
ope:='avg';
ELSE
ope:='sum';
END IF;
m:=t_time;
FOR reco IN times LOOP
c:=reco.QTM_DESCRIPTION;
m:=m||','||to_char(reco.QTM_VALUE)||','''||reco.QTM_DES_VALUE||'''';
END LOOP;
m:=m||',''...'')';
s:='select null link, mm "'||c||'", ii "'||OGG_ALIAS_SUM||' '||to_char(year)||'" from (';
s:=s||'select '||t_time||' tt, decode(t.'||m||' mm';
s:=s||', trunc('||ope||' ('||OGG_COL_SUM||'))'||' ii';
s:=s||' from D_TIME t, '||OGG_FACT_TAB||' f';
s:=s||' where t.TIM_AAAA = '||year;
s:=s||' and f.'||OGG_COL_TIME||' = t.TIM_KEY';
IF (g2) THEN
s:=s||' and '||OGG_COL_SUBGR||' = '''||p_subl||'''';
END IF;
IF (OGG_FACT_TAB='R_MAG_SALES' and w_warehouse is not null and w_warehouse <> 'null') THEN
s:=s||' and f.MS_WAREHOUSE = '''||w_warehouse||'''';
END IF;
IF (v_dims is not null and v_dims <> 'null') THEN
s:=s||' and f.'||OGG_COL_GROUP||' = '''||v_dims||'''';
END IF;
BEGIN
SELECT NVL(TRIM(SQL_CONDITION),'.') INTO sql_cond FROM Q_SQL_CONDITION WHERE SQL_CODE=cod_filter;
EXCEPTION
WHEN NO_DATA_FOUND THEN
sql_cond:='.';
END;
IF (sql_cond<>'.') THEN
s:=s||' and ('||sql_cond||')';
END IF;
s:=s||' group by t.'||t_time;
s:=s||' union ';
s:=s||'select t2.'||t_time||', decode(t2.'||m||', 0 from D_TIME t2';
s:=s||' where t2.'||t_time||' <> 0 and t2.'||t_time||' not in';
s:=s||' (select unique t3.'||t_time||' from D_TIME t3,'||OGG_FACT_TAB||' f3';
s:=s||' where t3.TIM_AAAA = '||year;
s:=s||' and t3.TIM_KEY = f3.'||OGG_COL_TIME;
BEGIN
SELECT NVL(TRIM(SQL_CONDITION),'.') INTO sql_cond FROM Q_SQL_CONDITION WHERE SQL_CODE=cod_filter;
EXCEPTION
WHEN NO_DATA_FOUND THEN
sql_cond:='.';
END;
IF (sql_cond<>'.') THEN
s:=s||' and ('||sql_cond||')';
END IF;
IF (OGG_FACT_TAB='R_MAG_SALES' and w_warehouse is not null and w_warehouse <> 'null') THEN
s:=s||' and f3.MS_WAREHOUSE = '''||w_warehouse||'''';
END IF;
IF (v_dims is not null and v_dims <> 'null') THEN
s:=s||' and f3.'||OGG_COL_GROUP||' = '''||v_dims||''')';
ELSE
s:=s||')';
END IF;
s:=s||' group by t2.'||t_time;
s:=s||')';
s:=s||' order by tt';
RETURN (s);
END;
To better understand this is the result of the function:
select null link, mm "Month", ii " 2018" from
(select TIM_MM tt, decode(t.TIM_MM,1,'January',2,'February',3,'March',4,'April',5,'May',6,'June',7,'July',8,'August',9,'September',10,'October',11,'November',12,'December','...') mm, trunc(sum (MS_FINAL_EXISTENCE)) ii from
D_TIME t, R_MAG_SALES f
where t.TIM_AAAA = 2018 and f.MS_TIM_BALANCE_DATE = t.TIM_KEY and f.MS_UNIT_OF_MEASURE = 'PZ' and f.MS_COD_CATEGORY = '000001' group by t.TIM_MM
union select t2.TIM_MM, decode(t2.TIM_MM,1,'January',2,'February',3,'March',4,'April',5,'May',6,'June',7,'July',8,'August',9,'September',10,'October',11,'November',12,'December','...'), 0 from
D_TIME t2
where t2.TIM_MM <> 0
and t2.TIM_MM not in (select unique t3.TIM_MM from D_TIME t3,R_MAG_SALES f3 where t3.TIM_AAAA = 2018 and t3.TIM_KEY = f3.MS_TIM_BALANCE_DATE and f3.MS_COD_CATEGORY = '000001') group by t2.TIM_MM) order by tt
Can enybody please help me, I just do not see what is wrong...
When you write the query in IR/CR, the bind variables :P2_OBJECT,:P2_YEAR are null.
So, your builder assumes the query as
select F_CHARTS(NULL,NULL,....)
into l_sql from dual;
So the compilation of PLSQL block fails
You can write the query as
select f_charts ( COALESCE(:P2_OBJECT, 'X'), COALESCE(:P2_YEAR, 0)....) from dual.
SO, you are actually sending some actual values to f_charts
You can also handle this in function to assume some value if inputs are null.

multiple IF inside cursor loop

after this question, I'm unable to evaluate with different IFs statements inside one single loop, my execution ends with ORA-01403: no data found
What I have:
Declaration:
CREATE OR REPLACE PACKAGE MYSCHEMA.MYPKG AS
FUNCTION MYFUNCTION ( description OUT VARCHAR2 ) RETURN INTEGER;
END MYPKG;
Body:
CREATE OR REPLACE PACKAGE BODY MYSCHEMA.MYPKG AS
FUNCTION MYFUNCTION ( description OUT VARCHAR2 ) RETURN INTEGER AS
CURSOR CUR_MYDATA IS
SELECT
o.name,
o.last_name,
o.id,
o.socnum
FROM
origin o
WHERE
1=1
AND o.name like upper ('a%');
TYPE t_name IS TABLE OF origin.name%TYPE;
TYPE t_lastname IS TABLE OF origin.last_name%TYPE;
TYPE t_id IS TABLE OF origin.id%TYPE;
TYPE t_socnum IS TABLE OF origin.socnum%TYPE;
l_name t_name;
l_lastname t_lastname;
l_id t_id;
l_socnum t_socnum;
retcode INTEGER := 0;
BEGIN
description := 'OK';
OPEN CUR_MYDATA;
LOOP
FETCH CUR_MYDATA BULK COLLECT INTO l_name,l_lastname,l_id,l_socnum;
EXIT WHEN l_name.count = 0;
for name in l_name.first .. l_name.last loop
IF l_socnum(name) IS NULL THEN
(select oo.socnum from other_origin where oo.id=l_id(name))
END IF;
IF length(l_lastname(name)) < 2 THEN
l_lastname(name) := 'default lastname';
END IF;
end loop;
forall i IN l_name.first .. l_name.last
INSERT INTO destiny (
d_name,
d_lastname,
d_id,
d_socnum)
VALUES (
l_name(i),
l_lastname(i),
l_id(i),
l_socnum(i));
END LOOP;
COMMIT;
RETURN retcode;
EXCEPTION
WHEN OTHERS THEN
description := SQLERRM;
retcode := SQLCODE;
CLOSE CUR_MYDATA;
RETURN retcode;
END MYFUNCTION;
END MYPKG;
But I got ORA-01403: no data found
I also tried:
for name in l_name.first .. l_name.last loop
IF l_socnum(name) IS NULL THEN
(select oo.socnum
into l_socnum(name)
from other_origin where oo.id=l_id(name))
for ln in l_name.first .. l_name.last loop
IF length(l_lastname(ln)) < 2 THEN
l_lastname(ln) := 'default lastname';
END IF;
end loop;
END IF;
end loop;
But error is the same.
So, what do you think that I'm missing when I loop more than once through my cursor evaluating differents columns?

ORA-01007: variable not in select list while fetch c2 into cursor2

I have oracle pl/sql procedure with below:
TYPE Paycomp2 IS RECORD(
Row_Id VARCHAR2(15),
Created DATE,
Created_By VARCHAR2(15),
Last_Upd DATE,
Last_Upd_By VARCHAR2(15),
Modification_Num NUMBER(10),
Conflict_Id VARCHAR2(15),
Comp_Price NUMBER(10),
Access_Level VARCHAR2(30),
Comp_Name VARCHAR2(30),
Depends_On VARCHAR2(30),
Gold_Cat VARCHAR2(30),
Order_Type VARCHAR2(30),
Parent_Id VARCHAR2(15),
Price_Plan VARCHAR2(30),
TYPE VARCHAR2(30),
Check_Flag VARCHAR2(1),
PREPAID_INIT_PRICE number(10),
DB_LAST_UPD date,
DB_LAST_UPD_SRC varchar2(50),
Unit_Type varchar2(30),
M2M_CATEGORY varchar2(30));
TYPE Paycomp IS REF CURSOR;
C2 Paycomp;
Cursor2 Paycomp2;
when I do the below operation
FETCH C2 INTO Cursor2;
I am getting this error :
ORA-01007: variable not in select list error.
This piece of script has worked previously.
How to resolve this issue?
script
Vordertype := 'Migration Prepaid - Postpaid';
Curcomp_Sql := Curcomp_Sql || Vordertype || '''' || ' union all ' || '' || Curcomp2sql || '' ||
Vordertype || '''';
OPEN C2 FOR Curcomp_Sql;
Sadmin.Pkg_Spliter.Prcsplitchar(Ppaycompstr, ';', Arrcomplist);
Vtotalcompprc := 0;
Arrcount := Arrcomplist.Count;
BEGIN
Dbms_output.put_line('reached17');
LOOP
FETCH C2
INTO Cursor2;
Dbms_output.put_line('reached18');
EXIT WHEN C2%NOTFOUND;
-- Processing each entry from Array
Compfndflg := 0;
dbms_output.put_line('arrCount 0: reached');
FOR Counter IN 1 .. Arrcount
LOOP
Vstrcommand := Arrcomplist(Counter);
dbms_output.put_line('arrCount : reached');
Sadmin.Pkg_Spliter.Prcsplitchar(Vstrcommand, '?', Arrdisclist);
IF Arrdisclist.Count <> 0 THEN
dbms_output.put_line('arrCount : reached1');
-- Extracting the ? seperated values and putting them into variables
Vcompname := Arrdisclist(1);
--dbms_output.put_line(CURSOR2.comp_name||':- count -'||COUNTER||'--'||VCOMPNAME);
BEGIN
-- Added by Accenture
IF Vcompname IS NOT NULL THEN
--dbms_output.put_line(CURSOR2.comp_name||':- count -'||COUNTER||'--'||ARRDISCLIST(1)||'-'||ARRDISCLIST(2)||'-'||ARRDISCLIST(3));
SELECT COUNT(0)
INTO v_Count_Exist
FROM Siebel.Cx_Paycomp_Mtx a, Siebel.Cx_Paycomp_Mtx b
WHERE a.Row_Id = b.Parent_Id
AND a.Order_Type = Vordertype
AND b.Type = 'Payment Component'
AND b.Comp_Name = Vcompname;
IF (v_Count_Exist = 0) THEN
Err_Msg := 'Invalid Payment Component in String';
Result_Out := '74';
Errflg := 1;
--dbms_output.put_line('Counter 2' || counter);
--dbms_transaction.rollback;
RAISE Error_Out;
END IF;
END IF;
--dbms_output.put_line('Counter 3' || CURSOR2.comp_name);
IF Vcompname = Cursor2.Comp_Name
--and VCOMPNAME != '3'
THEN
Compfndflg := 1;
EXIT;
END IF;
END;
END IF;
END LOOP;
---DBMS_OUTPUT.PUT_LINE('VCOMPNAME, COMPFNDFLG'||VCOMPNAME||','||COMPFNDFLG);
--dbms_output.put_line('CURSOR2.comp_name :'||CURSOR2.comp_name||' - COMPFNDFLG :'||COMPFNDFLG);
IF Compfndflg != 1 THEN
IF Temp_Comp_String IS NULL THEN
Temp_Comp_String := Cursor2.Comp_Name || '?0?;';
---DBMS_OUTPUT.PUT_LINE('STRING 1'||TEMP_COMP_STRING);
ELSE
Temp_Comp_String := Temp_Comp_String || Cursor2.Comp_Name || '?0?;';
---DBMS_OUTPUT.PUT_LINE('STRING 2'||TEMP_COMP_STRING);
END IF;
--- END IF;
ELSE
IF Temp_Comp_String IS NULL THEN
Temp_Comp_String := Arrdisclist(1) || '?' || Arrdisclist(2) || '?' ||
Arrdisclist(3) || ';';
---DBMS_OUTPUT.PUT_LINE('STRING 3'||TEMP_COMP_STRING);
ELSE
Temp_Comp_String := Temp_Comp_String || Arrdisclist(1) || '?' || Arrdisclist(2) || '?' ||
Arrdisclist(3) || ';';
---DBMS_OUTPUT.PUT_LINE('STRING 4'||TEMP_COMP_STRING);
END IF;
-- end if;
--- END IF;
END IF;
END LOOP;
END;
Curcomp_Sql VARCHAR2(2000) := 'SELECT mtx2.*
FROM siebel.CX_PAYCOMP_MTX mtx1, siebel.CX_PAYCOMP_MTX mtx2
WHERE mtx2.parent_id = mtx1.row_id
AND mtx2.comp_name <> ''Security Deposit''
AND mtx2.TYPE = ''Payment Component''
AND mtx1.order_type = ''';
Curcomp2sql VARCHAR2(2000) := 'SELECT mtx2.*
FROM siebel.CX_PAYCOMP_MTX mtx1, siebel.CX_PAYCOMP_MTX mtx2
WHERE mtx2.parent_id = mtx1.row_id
AND mtx2.comp_name = ''Security Deposit''
AND mtx2.TYPE = ''Payment Component''
AND mtx2.depends_on = ''ACCESS LEVEL''
AND mtx1.order_type = ''';
A simplified version of what you're seeing, with a dummy table and simple anonymous block:
create table t42 (id number, some_value varchar2(10));
declare
type t_rec is record(id number, some_value varchar2(10));
l_rec t_rec;
l_cur sys_refcursor;
begin
open l_cur for 'select * from t42';
fetch l_cur into l_rec;
close l_cur;
end;
/
PL/SQL procedure successfully completed.
To get the error you're seeing I just need to remove one of the table columns:
alter table t42 drop column some_value;
and run exactly the same code again:
declare
type t_rec is record(id number, some_value varchar2(10));
l_rec t_rec;
l_cur sys_refcursor;
begin
open l_cur for 'select * from t42';
fetch l_cur into l_rec;
close l_cur;
end;
/
ORA-01007: variable not in select list
ORA-06512: at line 10
The field list in the record type declared in the PL/SQL block no longer matches the column type in the cursor query. The record variable you're fetching into expects two columns (in my version; 22 in yours), but the query only gets one value.
You can (some would say should) specify all the columns you're selecting explicitly, but assuming you're actually referring to them all later you would then have done the equivalent of:
open l_cur for 'select id, some_value from t42';
which would still have errored after the column removal, though a bit more helpfully perhaps:
ORA-00904: "SOME_VALUE": invalid identifier
ORA-06512: at line 9
Since you're currently intending to get all columns from a single table, you could also have used the %rowtype syntax instead of your own record type:
declare
l_rec t42%rowtype;
l_cur sys_refcursor;
begin
open l_cur for 'select * from t42';
fetch l_cur into l_rec;
close l_cur;
end;
/
which with this trivial example runs successfully. You'll still have a problem though as soon as you refer to the removed column, assuming it's still part of the record:
declare
l_rec t42%rowtype;
l_cur sys_refcursor;
begin
open l_cur for 'select * from t42';
fetch l_cur into l_rec;
dbms_output.put_line(l_rec.some_value);
close l_cur;
end;
/
ORA-06550: line 7, column 30:
PLS-00302: component 'SOME_VALUE' must be declared
ORA-06550: line 7, column 3:
PL/SQL: Statement ignored
(Using %rowtype would give you some breathing space if a column was added, as it would just be ignored, unless and until you added code to refer to that record field. But with your code you'd get ORA-00932 inconsistent data types, rather than ORA-01007, so that doesn't seem to be what's happening here.)
If you aren't referring to the removed column/field anywhere then you shouldn't be selecting it anyway. Change the record type to only include the fields you actually need, and only get the corresponding columns in the cursor query.
If you are referring to the removed column/field then you're stuck anyway - you'll have find out what was removed and why, and then either fix your code to not refer to it (if that makes sense), or get that change reverted.

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